<HTML>
<HEAD>
<TITLE>GigaBASE Object-Relational database system</TITLE>
<UL>
<LI> <A HREF = "#introduction">Introduction</A>
<LI> <A HREF = "#sql">Query language</A>
  <UL>
  <LI> <A HREF = "#structure">Structures</A>
  <LI> <A HREF = "#array">Arrays</A>
  <LI> <A HREF = "#string">Strings</A>
  <LI> <A HREF = "#reference">References</A>
  <LI> <A HREF = "#rectangle">Rectangle</A>
  <LI> <A HREF = "#function">Functions</A>
  </UL>
<LI> <A HREF = "#cpp">C++ interface</A>
  <UL>
  <LI> <A HREF = "#table">Table</A>
  <LI> <A HREF = "#query">Query</A>
  <LI> <A HREF = "#cursor">Cursor</A>
  <LI> <A HREF = "#database">Database</A>
  </UL>
<LI> <A HREF = "#cli">CLI - call level interface</A>
  <UL>
  <LI> <A HREF = "#cli_errors">CLI error codes</A>
  <LI> <A HREF = "#cli_types">CLI supported types</A>
  <LI> <A HREF = "#cli_open">cli_open</A>
  <LI> <A HREF = "#cli_close">cli_close</A>
  <LI> <A HREF = "#cli_clear_connection_pool">cli_close_connection</A>
  <LI> <A HREF = "#cli_statement">cli_statement</A>
  <LI> <A HREF = "#cli_parameter">cli_parameter</A>
  <LI> <A HREF = "#cli_column">cli_column</A>
  <LI> <A HREF = "#cli_array_column">cli_array_column</A>
  <LI> <A HREF = "#cli_fetch">cli_fetch</A>
  <LI> <A HREF = "#cli_insert">cli_insert</A>
  <LI> <A HREF = "#cli_get_first">cli_get_first</A>
  <LI> <A HREF = "#cli_get_last">cli_get_last</A>
  <LI> <A HREF = "#cli_get_next">cli_get_next</A>
  <LI> <A HREF = "#cli_get_prev">cli_get_prev</A>
  <LI> <A HREF = "#cli_get_oid">cli_get_oid</A>
  <LI> <A HREF = "#cli_update">cli_update</A>
  <LI> <A HREF = "#cli_remove">cli_remove</A>
  <LI> <A HREF = "#cli_free">cli_free</A>
  <LI> <A HREF = "#cli_commit">cli_commit</A>
  <LI> <A HREF = "#cli_abort">cli_abort</A>
  <LI> <A HREF = "#cli_show_tables">cli_show_tables</A>
  <LI> <A HREF = "#cli_describe">cli_describe</A>
  <LI> <A HREF = "#cli_create_table">cli_create_table</A>
  <LI> <A HREF = "#cli_alter_table">cli_alter_table</A>
  <LI> <A HREF = "#cli_drop_table">cli_drop_table</A>
  <LI> <A HREF = "#cli_alter_index">cli_alter_index</A>
  <LI> <A HREF = "#cli_freeze">cli_freeze</A>
  <LI> <A HREF = "#cli_unfreeze">cli_unfreeze</A>
  <LI> <A HREF = "#cli_seek">cli_seek</A>
  <LI> <A HREF = "#cli_skip">cli_skip</A>
  </UL>
<LI> <A HREF = "#localcli">Local implementation of CLI</A>
  <UL>
  <LI> <A HREF = "#cli_create">cli_create</A>
  <LI> <A HREF = "#cli_attach">cli_attach</A>
  <LI> <A HREF = "#cli_detach">cli_detach</A>
  <LI> <A HREF = "#cli_prepare_query">cli_prepare_query</A>
  <LI> <A HREF = "#cli_execute_query">cli_execute_query</A>
  <LI> <A HREF = "#cli_insert_struct">cli_insert_struct</A>
  </UL>
<LI> <A HREF = "#phpcli">Interface to PHP language</A>
  <UL>
  <LI> <A HREF = "#cliphp_errors">Status codes</A>
  <LI> <A HREF = "#cliphp_types">Supported types</A>
  <LI> <A HREF = "#gb_connection_pool">gb_connection_pool</A>
     <UL>
     <LI> <A HREF = "#new_connection">new_connection</A>
     <LI> <A HREF = "#release_connection">release_connection</A>
     <LI> <A HREF = "#close">close</A>
     </UL>
  <LI> <A HREF = "#gb_connection">gb_connection</A>
     <UL>
     <LI> <A HREF = "#con_open">open</A>
     <LI> <A HREF = "#con_close">close</A>
     <LI> <A HREF = "#con_create_statement">create_statement</A>
     <LI> <A HREF = "#con_insert">insert</A>
     <LI> <A HREF = "#con_commit">commit</A>
     <LI> <A HREF = "#con_rollback">rollback</A>
     <LI> <A HREF = "#con_show_tables">show_tables</A>
     <LI> <A HREF = "#con_describe">describe_table</A>
     </UL>
  <LI> <A HREF = "#gb_statement">gb_statement</A>
     <UL>
     <LI> <A HREF = "#stmt_bind_parameter">bind_parameter</A>
     <LI> <A HREF = "#stmt_bind_column">bind_column</A>
     <LI> <A HREF = "#stmt_bind_object">bind_object</A>
     <LI> <A HREF = "#stmt_bind_array">bind_array</A>
     <LI> <A HREF = "#stmt_fetch">fetch</A>
     <LI> <A HREF = "#stmt_fetch_objects">fetch_objects</A>
     <LI> <A HREF = "#stmt_fetch_tuples">fetch_tuples</A>
     <LI> <A HREF = "#stmt_insert">insert</A>
     <LI> <A HREF = "#stmt_get_first">get_first</A>
     <LI> <A HREF = "#stmt_get_last">get_last</A>
     <LI> <A HREF = "#stmt_get_next">get_next</A>
     <LI> <A HREF = "#stmt_get_prev">get_prev</A>
     <LI> <A HREF = "#stmt_get_oid">get_oid</A>
     <LI> <A HREF = "#stmt_update">update</A>
     <LI> <A HREF = "#stmt_remove">remove</A>
     <LI> <A HREF = "#stmt_free">free</A>
     </UL> 
  <LI> <A HREF = "#gb_reference">gb_reference</A>
  </UL>
<LI> <A HREF = "javacli/index.html">Interface to Java language</A>
<LI> <A HREF = "#advanced">Delayed transactions and online backup scheduler</A>
<LI> <A HREF = "#optimization">Query optimization</A>
  <UL>
  <LI> <A HREF = "#indices">Using indices in queries</A>
  <LI> <A HREF = "#inverse">Inverse references</A>
  <LI> <A HREF = "#par">Parallel query execution</A>
  </UL>
<LI> <A HREF = "#replication">GigaBASE replication mechanism</A>
<LI> <A HREF = "#gist">Generalized search tree</A>
<LI> <A HREF = "#implementation">GigaBASE implementation issues</A>
  <UL>
  <LI> <A HREF = "#memory">Memory allocation</A>
  <LI> <A HREF = "#transaction">Transactions</A>
  <LI> <A HREF = "#recovery">Recovery</A>
  <LI> <A HREF = "#btree">B-tree</A>
  </UL>
<LI> <A HREF = "#subsql">Interactive SQL</A>
<LI> <A HREF = "#www">API for development Web applications</A>
<LI> <A HREF = "#examples">Examples of GigaBASE applications</A>
  <UL>
  <LI> <A HREF = "#guess">Example: game "Guess an animal"</A>
  <LI> <A HREF = "#testdb">Example: various types of queries</A>
  <LI> <A HREF = "#testperf">Performance test</A>
  <LI> <A HREF = "#bugdb">Bug tracking database</A>
  <LI> <A HREF = "#clidb">Clients-Managers database</A>
  </UL>
<LI> <A HREF = "#quick">Quick start</A>
<LI> <A HREF = "#dbsize">Reducing initial size of the database file</A>
<LI> <A HREF = "#sharing">Sharing of classes between different databases</A>
<LI> <A HREF = "docs/html/index.html">Documentation generated by Doxygen</A>
<LI> <A HREF = "#distribution">Distribution terms</A>
</UL>

<BODY>
<HR>
<H2><A NAME = "introduction">Introduction</A></H2>

GigaBASE is object-relational database system with the same programming
interface as FastDB main memory DBMS, but using a page pool instead of
mapping database file to the memory. That is why GigaBASE is able to handle
databases which size exceeds size of computers virtual memory.
As FastDB, GigaBASE provides a very convenient and efficient C++ interface.
GigaBASE doesn't support client-server architecture and provides concurrent
access to the database only for different threads within one process.
GigaBASE is most efficient for applications fetching records using indices or
direct object references. High speed of query
execution is provided by elimination of data transfer overhead and
very effective locking implementation.
Synchronization of concurrent database access is implemented in GigaBASE
by means of atomic instructions, adding almost
no overhead to query processing. GigaBASE uses modified B-tree indices
to provide fast access to disk resident data (with minimal disk read operations).
<P>

GigaBASE supports transactions, online backups and automatic recovery
after system crash. Transaction commit protocol is based on
shadow pages algorithm, performing atomic update of database.
Recovery can be done very fast, providing
high availability for critical applications. Moreover, elimination
of transaction logs improves total system performance and leads to more
effective usage of system resources.<P>

GigaBASE is application-oriented database. Database tables are constructed
using
information about application classes. GigaBASE supports automatic scheme
evaluation, allowing you to do changes only in one place - in your
application classes. GigaBASE provides flexible and convenient interface
for retrieving data from database. SQL-like query language is used
to specify queries, and such post-relational capabilities as non-atomic
fields, nested arrays, user-defined types and methods, direct interobject
references simplifies design of database application and makes them more
efficient.<P>

GigaBASE is able to efficiently handle databases with several millions objects
and up to terabyte size even at computers having not so much physical
memory. Page pool using LRU strategy for page replacement and B-tree
indices minimize number of disk operations and so provide high system
performance.<P>


<H2><A NAME = "sql">Query language</A></H2>

GigaBASE supports query language with SQL-like syntax. GigaBASE uses notation more
popular for object-oriented programming then for relational database.
Table rows are considered as object instances and the table - as class of these
objects. Unlike SQL, GigaBASE is oriented on work with objects instead of SQL
tuples. So the result of each query execution  is a set of objects of one
class. The main differences of GigaBASE query language from standard SQL are:<P>

<OL>
<LI> There are no joins of several tables and nested subqueries. Query always
returns set of objects from one table.
<LI> Standard C types are used for atomic table columns.
<LI> There are no NULL values, except null references.
I am completely agree with C.J. Date critics of three-value logic and his
proposal to use default values instead.
<LI> Structures and arrays can be used as record components. Special
<B>exists</B> quantor is provided for locating element in arrays.
<LI> User methods can be defined for table records (objects) as well as
for record components.
<LI> User functions with single string or numeric argument can be defined by
application.
<LI> References between objects are supported including automatic support
of inverse references.
<LI>Construction <code>start from follow by</code> performs recursive records
traversal using references.
<LI> As far as query language is deeply integrated with C++ classes, case
sensitive mode is used for language identifiers as well as for keywords.
<LI> No implicit conversion of integer and floating types is done to string
representation. If such conversion is need, it should be done explicitly.
</OL><P>

The following rules in BNF-like notation specifies grammar of
GigaBASE query language search predicate:<P>

<TABLE BORDER ALIGN="center">
<CAPTION>Grammar conventions</CAPTION>
<TR><TH>Example</TH><TH>Meaning</TH></TR>
<TR><TD><I>expression</I></TD><TD>non-terminals</TD></TR>
<TR><TD><B>not</B></TD><TD>terminals</TD></TR>
<TR><TD ALIGN="center">|</TD><TD>disjoint alternatives</TD></TR>
<TR><TD>[<B>not</B>]</TD><TD>optional part</TD></TR>
<TR><TD>{<B>1</B>..<B>9</B>}</TD><TD>repeat zero or more times</TD></TR>
</TABLE><P>

<PRE>
<I>select-condition</I> ::= [ <I>expression</I> ] [ <I>traverse</I> ] [ <I>order</I> ] [ <I>limit</I> )
<I>expression</I> ::= <I>disjunction</I>
<I>disjunction</I> ::= <I>conjunction</I>
        | <I>conjunction</I> <B>or</B> <I>disjunction</I>
<I>conjunction</I> ::= <I>comparison</I>
        | <I>comparison</I> <B>and</B> <I>conjunction</I>
<I>comparison</I> ::= <I>operand</I> <B>=</B> <I>operand</I>
        | <I>operand</I> <B>!=</B> <I>operand</I>
        | <I>operand</I> <B>&lt;&gt;</B> <I>operand</I>
        | <I>operand</I> <B>&lt;</B> <I>operand</I>
        | <I>operand</I> <B>&lt;=</B> <I>operand</I>
        | <I>operand</I> <B>&gt;</B> <I>operand</I>
        | <I>operand</I> <B>&gt;=</B> <I>operand</I>
        | <I>operand</I> (<B>not</B>) <B>like</B> <I>operand</I>
        | <I>operand</I> (<B>not</B>) <B>like</B> <I>operand</I> <B>escape</B> <I>string</I>
        | <I>operand</I> (<B>not</B>) <B>in</B> <I>operand</I>
        | <I>operand</I> (<B>not</B>) <B>in</B> <I>expressions-list</I>
        | <I>operand</I> (<B>not</B>) <B>between</B> <I>operand</I> <B>and</B> <I>operand</I>
	| <I>operand</I> <B>is</B> (<B>not</B>) <B>null</B>
<I>operand</I> ::= <I>addition</I>
<I>additions</I> ::= <I>multiplication</I>
        | <I>addition</I> <B>+</B>  <I>multiplication</I>
        | <I>addition</I> <B>||</B> <I>multiplication</I>
        | <I>addition</I> <B>-</B>  <I>multiplication</I>
<I>multiplication</I> ::= <I>power</I>
        | <I>multiplication</I> <B>*</B> <I>power</I>
        | <I>multiplication</I> <B>/</B> <I>power</I>
<I>power</I> ::= <I>term</I>
        | <I>term</I> <B>^</B> <I>power</I>
<I>term</I> ::= <I>identifier</I> | <I>number</I> | <I>string</I>
        | <B>true</B> | <B>false</B> | <B>null</B>
	| <B>current</B> | <B>first</B> | <B>last</B>
	| <B>(</B> expression <B>)</B>
        | <B>not</B> <I>comparison</I>
	| <B>-</B> term
	| <I>term</I> <B>[</B> expression <B>]</B>
	| <I>identifier</I> <B>.</B> <I>term</I>
	| <I>function</I> <I>term</I>
        | <B>exists</B> <I>identifier</I> <B>:</B> <I>term</I>
	| <I>parameter</I>
<I>function</I> ::= <B>abs</B> | <B>length</B> | <B>lower</B> | <B>upper</B>
        | <B>integer</B> | <B>real</B> | <B>string</B> | <I>user-function</I>
<I>string</I> ::= <B>'</B> { { <I>any-character-except-quote</I> } (<B>''</B>) } <B>'</B>
<I>expressions-list</I> ::= <B>(</B> <I>expression</I> { <B>,</B> <I>expression</I> } <B>)</B>
<I>order</I> ::= <B>order by</B> <I>sort-list</I>
<I>sort-list</I> ::= <I>field-order</I> { <B>,</B> <I>field-order</I> }
<I>field-order</I> ::= [<B>length</B>] <I>field</I> (<B>asc</B> | <B>desc</B>)
<I>field</I> ::= <I>identifier</I> { <B>.</B> <I>identifier</I> }
<I>traverse</I> ::= <B>start from</B> <I>field</I> [ <B>follow by</B> ( <B>next</B> | <B>previous</B> | <I>fields-list</I> ) ]
<I>limit</I>::= <B>limit</B> [ <I>start-position</I> <B>,</B> ] <I>max-selected</I>
<I>max-selected</I> ::= <B>integer</B> | <I>parameter</I>
<I>start-position</I> ::= <B>integer</B> | <I>parameter</I>
<I>fields-list</I> ::=  <I>field</I> { <B>,</B> <I>field</I> }
<I>user-function</I> ::= <I>identifier</I>
</PRE><P>

Identifiers are case sensitive, begin with a..z, A..Z, '_' or '$'
character, contain only a-z, A..Z, 0..9 '_' or '$' characters, and
do not duplicate a SQL reserved words.<P>

<TABLE WIDTH=100%>
<CAPTION>List of reserved words</CAPTION>
<TR><TD>abs</TD><TD>and</TD><TD>area</TD><TD>asc</TD><TD>between</TD></TR>
<TR><TD>by</TD><TD>current</TD><TD>desc</TD><TD>escape</TD><TD>exists</TD></TR>
<TR><TD>false</TD><TD>first</TD><TD>follow</TD><TD>from</TD><TD>in</TD></TR>
<TR><TD>integer</TD><TD>is</TD><TD>length</TD><TD>like</TD><TD>last</TD></TR>
<TR><TD>limit</TD><TD>lower</TD><TD>not</TD><TD>null</TD><TD>or</TD></TR>
<TR><TD>overlaps</TD><TD>real</TD>><TD>rectangle</TD><TD>start</TD><TD>string</TD></TR>
<TR><TD>upper</TD><TD>true</TD></TR>
</TABLE><P>

ANSI-standard comments may also be used. All character from double-hyphen to
the end of the line are ignored.<P>

GigaBASE extends ANSI standard SQL operations by supporting bit manipulation
operations. Operators <code>and</code>/<code>or</code> can be applied not only
to boolean operands but also to operands of integer type. Result of applying
<code>and</code>/<code>or</code> operator to integer operands is integer
value with bits set by bit-AND/bit-OR operation. Bits operations can be used
for efficient implementation of small sets. Also rasing to a power
operation <B>^</B> is supported by GigaBASE for integer and floating point
types.<P>

Starting from 2.51 version GigaBASE supports <code>LIMIT [S,]N</code>
construction in queries. It is more useful, flexible and efficient way to 
restrict number of selected records than limit specified for the cursor. 
First parameter <code>S</code> (if present)
specifies number of record to be skipped (so <code>S</code> records
which match search criteria will not be selected). Parameter <code>N</code> 
specifies maximal number of records to be selected. So if you want to show
first ten results of the query at the screen, you should append
<code>limit 0,10</code> to the query. If you want to show next 10 results,
then append <code>limit 10,10</code>...<P>
It is possible to use parameters of <code>int4</code> type instead of 
constants for specifying <code>S</code> and <code>N</code>. 
In this case, the same precompiled statement can be used 
for fetching parts of the list.<P>

Limit construction correctly works when <code>order by</code> clause is present. 
If there is index for variable in order part, then records are inspected in requested order,
so sort is not needed and after fetching <code>N</code> records we can finish
query execution. Otherwise, all records will be selected, sorted and then 
only records from <code>[S,N]</code> interval are left and other are removed from 
the selection.<P>


<H3><A NAME = "structure">Structures</A></H3>

GigaBASE accepts structures as components of records. Field of the structure
can be accessed using standard dot notation: <code>company.address.city</code>
<P>

Structure fields can be indexed and used in <code>order by</code>
specification. Structures can contain other structures as their components
and there are no limitations on nesting level.<P>

Programmer can define methods for structures, which can be used
in queries with the same syntax as normal structure components.
Such methods should have no arguments except pointer to the object to which
they belong (<code>this</code> pointer in C++), and should return
atomic value (of boolean, numeric, string or reference type).
Also method should not change object instance (immutable method).
If method returns string, then this string should be allocated using
<code>new char</code> operator, because it will be deleted after copying of
its value.
So user-defined methods can be used for creation <I>virtual</I> components -
components which are not stored in database, but instead if this are calculated
using values of other components. For example, GigaBASE <code>dbDateTime</code>
type contains only integer timestamp component and such methods
as <code>dbDateTime::year()</code>, <code>dbDateTime::month()</code>...
So it is possible to specify queries like: "<code>delivery.year = 1999</code>"
in application, where <code>delivery</code> record field has
<code>dbDateTime</code> type. Methods are executed in the context of
application, where they are defined, and are not available to other
applications and interactive SQL.<P>

<H3><A NAME = "array">Arrays</A></H3>
GigaBASE accepts arrays with dynamic length as components of records.
Multidimensional arrays are not supported, but it is possible to
define array of arrays. It is possible to sort records in the result set
by length of array field.
GigaBASE provides a set of special constructions for dealing with arrays:<P>

<OL>
<LI>It is possible to get the number of elements in the array by
<code>length()</code> function.

<LI>Array elements can be fetched by <code>[]</code> operator.
If index expression is out of array range, then exception will be raised.

<LI>Operator <code>in</code> can be used for checking if array contains
value specified by left operand. This operation can be used only for arrays of
atomic types: with boolean, numeric, reference or string components.

<LI>Array can be updated using <code>update</code> method which creates copy of the array and returns
non-constant reference.

<LI>Iteration through array elements is performed by <code>exists</code>
operator. Variable specified after <code>exists</code> keyword can be used
as index in arrays in the expression preceded by <code>exists</code>
quantor. This index variable will iterate through all possible array
index values, until value of expression will become <code>true</code> or
index runs out of range. Condition

<PRE>
        exists i: (contract[i].company.location = 'US')
</PRE>

will select all details which are shipped by companies
located in US, while query

<PRE>
        not exists i: (contract[i].company.location = 'US')
</PRE>

will select all details which are shipped only from companies outside US.<P>

Nested <code>exists</code> clauses are allowed. Using of nested
<code>exists</code> quantors is equivalent to nested loops using correspondent
index variables. For example query

<PRE>
        exists colon: (exists row: (matrix[colon][row] = 0))
</PRE>

will select all records, containing 0 in elements of <code>matrix</code>
field, which has type array of array of integer.
This construction is equivalent to the following
two nested loops:

<PRE>
       bool result = false;
       for (int colon = 0; colon < matrix.length(); colon++) {
            for (int row = 0; row < matrix[colon].length(); row++) {
	         if (matrix[colon][row] == 0) {
                     result = true;
		     break;
                 }
            }
       }
</PRE>

Order of using indices is significant! Result of the following query execution
<PRE>
        <code>exists row: (exists colon: (matrix[colon][row] = 0))</code>
</PRE>

will be completely different with result of previous query. The program can
simply hang in last case due to infinite loop for empty matrices.
</OL>


<H3><A NAME = "string">Strings</A></H3>

All strings in GigaBASE have varying length and programmer should not
worry about specification of maximal length for character fields.
All operations acceptable for arrays are also applicable to strings.
In addition to them strings have a set their own operations.
First of all string can be compared with each other using standard
relation operators. At the current moment GigaBASE supports only
ASCII character set (corresponds to type <code>char</code> in C) and
byte-by-byte comparison of strings ignoring locality settings.<P>

Construction <code>like</code> can be used for
matching string with a pattern containing special wildcard characters
'%' and '_'. Character '_' matches any single character, while character
'%' matches any number of characters (including 0). Extended form of
<code>like</code> operator with <code>escape</code> part can be used
to handle characters '%' and '_' in the pattern as normal characters if
they are preceded by special escape character, specified after
<code>escape</code> keyword.<P>

It is possible to search substring within string by <code>in</code>
operator. Expression <code>('blue' in color)</code> will be true
for all records which <code>color</code> fields contains 'blue' word.
If length of searched string is greater than some threshold value
(currently 512), then Boyer-Moore substring search algorithm is used instead
of straightforward search implementation.<P>

Strings can be concatenated by <code>+</code> or <code>||</code> operators.
Last one was added only for compatibility with ANSI SQL standard.
As far as GigaBASE doesn't support implicit conversion to string type in
expressions, semantic of operator <code>+</code> can be redefined for
strings.<P>


<H3><A NAME = "reference">References</A></H3>

References can be dereferenced using the same dot notation as used for
accessing structure components. For example the following query

<PRE>
        company.address.city = 'Chicago'
</PRE>

will access record referenced by <code>company</code> component of
<code>Contract</code> record and extract city component of
<code>address</code> field of referenced record from <code>Supplier</code>
table.<P>

References can be checked for <code>null</code> by <code>is null</code>
or <code>is not null</code> predicates. Also references can be compared for
equality with each other as well as with special <code>null</code>
keyword. When null reference is dereferenced, exception is raised
by GigaBASE.<P>

There is special keyword <code>current</code>, which can be used to get
reference to current record during table search. Usually <code>current</code>
keyword is used for comparison of current record identifier with
other references or locating it within array of references.
For example, the following query will search in <code>Contract</code>
table for all active contracts
(assuming that field <code>canceledContracts</code> has
<code>dbArray&lt; dbReference&lt;Contract&gt; &gt;</code> type):

<PRE>
        current not in supplier.canceledContracts
</PRE><P>

GigaBASE provides special construction for recursive traverse of records by
references:

<PRE>
     <code>start from</code> <I>root-references</I>
     [ <code>follow by</code> ( <B>next</B> | <B>previous</B> | <I>list-of-reference-fields</I> ) ]
</PRE>

First part of this construction is used to specify root objects.
Nonterminal <I>root-references</I> should be variable of reference or
array of reference type. Two special keyword <code>first</code> and
<code>last</code> can be used here, locating first/last record in the table
correspondingly.
If you want to check for some condition all records
referenced by array of references or single reference field, then this
construction can be used without <code>follow by</code> part.<P>

If you specify follow by part, then GigaBASE will recursively traverse table
records starting from root references and using list of reference fields
<I>list-of-reference-fields</I> for transition between records.
<I>list-of-reference-fields</I> should consists of fields of
reference or array of reference type. Alternatively you can sepcify <B>next</B>
or <B>previous</B> preudofields, which refer to next or previous record in the table
(all records in GigaBASE table are linked in L2 list, new records are appended at the
end of the list).<P>

Traverse is done in depth first
top-left-right order (first we visit parent node and then siblings in
left-to-right order). Recursion is terminated when null reference is accessed
or already visited record is referenced. For example the following
query will search tree records with weight larger than 1 in TLR order:<P>

<PRE>
        "weight > 1 start from first follow by left, right"
</PRE><P>

For the following tree:

<PRE>
                              A:1.1
              B:2.0                             C:1.5
      D:1.3         E:1.8                F:1.2         G:0.8
</PRE>

result of query execution will be:

<PRE>
('A', 1.1), ('B', 2.0), ('D', 1.3), ('E', 1.8), ('C', 1.5), ('F', 1.2)
</PRE>


As was already mentioned GigaBASE always manipulates with objects and doesn't accept joins.
Joins can be implemented using references. Consider the classical
<code>Supplier-Shipment-Detail</code> examples:

<PRE>
struct Detail {
    char const* name;
    double      weight;

    TYPE_DESCRIPTOR((KEY(name, INDEXED), FIELD(weight)));
};

struct Supplier {
    char const* company;
    char const* address;

    TYPE_DESCRIPTOR((KEY(company, INDEXED), FIELD(address)));
};

struct Shipment {
    dbReference&lt;Detail&gt;   detail;
    dbReference&lt;Supplier&gt; supplier;
    int4                  price;
    int4                  quantity;
    dbDateTime            delivery;

    TYPE_DESCRIPTOR((KEY(detail, HASHED), KEY(supplier, HASHED),
		     FIELD(price), FIELD(quantity), FIELD(delivery)));
};
</PRE>

We want to get information about delivery of some concrete details from some concrete
suppliers. In relational database this query will be written something like this:

<PRE>
     select from Supplier,Shipment,Detail where
                 Supplier.SID = Shipment.SID and Shipment.DID = Detail.DID
		 and Supplier.company like ? and Supplier.address like ?
		 and Detail.name like ?
</PRE>

In GigaBASE this request should be written as:

<PRE>
     dbQuery q = "detail.name like",name,"and supplier.company like",company,
	         "and supplier.address like",address,"order by price";
</PRE>

GigaBASE will first perform index search in the table <code>Detail</code> for details
matching the search condition. Then it performs another index search to locate shipment
records referencing selected details. Then sequential search is used to check the rest of
select predicate.
<P>

<H3><A NAME = "rectangle">Rectangle</A></H3>

GigaBASE has builtin support of spatial data. It provides <code>rectangle</code> type.
By default it has dimension 2 and integer coordinate types. It is possible to easily change
dimension or use floating point coordinates, but recompilation of GigaBASE is needed in 
this case.<P>

It is possible to use this type not only in geographical system for 
representing spatial objects but also in many other cases when date is organized as hyper-cube and queries specify range of values for each dimension, for example:

<PRE>
      select * from CAR where price between 20000 and 30000 
                          and producedYear between 1997 and 1999 
                          and mileage between 50000 and 100000;
</PRE>

If <code>%lt;price, producedYear, milage&gt;</code> are dimensions of the rectangle, 
then this query can be executed using only one indexed search in R-Tree.<P>

Rectangle fields can be indexed - <B>R-Tree</B> index is used in this case
The R-tree provides fast access to spatial data. Basically the idea behind
the R-Tree and the B-Tree are the same:
use a hierarchical structure with a high branching factor to reduce the
number of disk accesses. The R-tree is the extension of the B_tree for a
multidimensional object. A geometric object is represented by its minimum 
bounding rectangle (MBR). Non-leaf nodes contain entries of the form 
(R,<I>ptr</I>) where <I>ptr</I> is a pointer to a child node in the R-tree; R 
is the MBR that covers all rectangles in the child node. Leaf nodes contain 
entries of the form (obj-id, R) where
obj-id is a pointer to the object, and R is the MBR of the object. The main 
innovation in the R-tree is that the father nodes are allowed to overlap. By
this means the R-tree guarantees at least 50% space utilization and remains 
balanced. 
The first R-tree implementation was proposed by Guttman. The Gigabase <B>R-Tree</B>
class is based on Guttman's implementation with a quadratic split algorithm.
The quadratic split algorithm is the one that achieves the best trade-off
between splitting time and search performance.<P>

Rectangle class provides method for calculating distance between two rectangle, 
rectangle area, checking whether two rectangle overlap or one contains another.
Rectangle is specified by coordinates of two it's vertices. Rectangle class
contains array of coordinates. Coordinates of first vertex are placed at the 
beginning of array, and then - coordinates of another vertex.
Each coordinate of first vertex should not be large than correspondent coordinate of 
the second vertex. Singular rectangle with one or more coordinates of first vertex equals 
to the correspondent coordinate of the second vertex are allowed - this is a way of storing
points in the database.<P>

SubSQL provides some special operators for dealing with rectangle. First of all - 
all comparison operators can be used with the following semantic:<P>

<TABLE BORDER ALIGN=CENTER>
<TR><TD><code>a == b</code></TD><TD>Rectangle <code>a</code> is the same as rectangle <code>b</code></TD></TR>
<TR><TD><code>a != b</code></TD><TD>Rectangle <code>a</code> is not the same as rectangle <code>b</code></TD></TR>
<TR><TD><code>a &lt;= b</code></TD><TD>Rectangle <code>b</code> contains rectangle <code>a</code></TD></TR>
<TR><TD><code>a &lt; b</code></TD><TD>Rectangle <code>b</code> contains rectangle <code>a</code> and them are not the same</TD></TR>
<TR><TD><code>a &gt;= b</code></TD><TD>Rectangle <code>a</code> contains rectangle <code>b</code> and are not the same</TD></TR>
<TR><TD><code>a &gt; b</code></TD><TD>Rectangle <code>b</code> contains rectangle <code>a</code> and them are not the same</TD></TR>
</TABLE><P>

Also SubSQL provides <code>overlaps</code> and <code>in</code> operators.
First checks if two rectangles overlap, the second is equivalent to <code>&lt;=</code> operator.
Rectangles can be added - result is minimal rectangle containing both rectangles-operands.
It is possible to access rectangle as array of coordinates - using <code>[index]</code>
notation. Coordinates in query are always returned as real numbers.<P>

Optimizer is able to use spatial index for all comparison operators (except <code>!=</code>)
and for <code>overlaps</code> operator.<P>


<H3><A NAME = "function">Functions</A></H3>
<TABLE BORDER ALIGN="center">
<CAPTION>Predefined functions</CAPTION>
<TR><TH>Name</TH><TH>Argument type</TH><TH>Return type</TH><TH>Description</TH></TR>
<TR><TD>abs</TD><TD>integer</TD><TD>integer</TD><TD>absolute value of the argument</TD></TR>
<TR><TD>abs</TD><TD>real</TD><TD>real</TD><TD>absolute value of the argument</TD></TR>
<TR><TD>area</TD><TD>rectangle</TD><TD>real</TD><TD>area of the rectangle</TD></TR>
<TR><TD>integer</TD><TD>real</TD><TD>integer</TD><TD>conversion of real to integer</TD></TR>
<TR><TD>length</TD><TD>array</TD><TD>integer</TD><TD>number of elements in array</TD></TR>
<TR><TD>lower</TD><TD>string</TD><TD>string</TD><TD>lowercase string</TD></TR><TR><TD>real</TD><TD>integer</TD><TD>real</TD><TD>conversion of integer to real</TD></TR>
<TR><TD>string</TD><TD>integer</TD><TD>string</TD><TD>conversion of integer to string</TD></TR>
<TR><TD>string</TD><TD>real</TD><TD>string</TD><TD>conversion of real to string</TD></TR>
<TR><TD>upper</TD><TD>string</TD><TD>string</TD><TD>uppercase string</TD></TR>
</TABLE><P>

GigaBASE  allows user to define its own functions and operators.
Function should have at least one but no more than 3 parameters of string, integer, 
boolean, reference or user defined (raw binary) type. It should return value of integer, real, string or
boolean type.<P>
User functions should be registered by the <code>USER_FUNC(f)</code> macro, 
which creates a static object of the <code>dbUserFunction</code> class, binding 
the function pointer and the function name.<P>
There are two ways of implementing these functions in application.
First can be used only for functions with one argument. This argument should be of <code>int8, real8,
char_t*</code> types. And the function return type should be <code>int8, real8, char_t*</code> or <code>bool</code>.
If function has more than one parameters or it can accept parameters of different types (polymorphism)
then parameters should be passed as reference to <code>dbUserFunctionArgument</code> structure.
This structure contains <code>type</code> field, which value can be used in function implementation to
detect type of passed argument and union with argument value.
The following table contains mapping between argument types and where the value should be taken from:<P>

<TABLE BORDER ALIGN=CENTER>
<TR><TH>Argument type</TH><TH>Argument value</TH><TH>Argument value type</TH></TR>
<TR><TD><code>dbUserFunctionArgument::atInteger</code></TD><TD><code>u.intValue</code></TD><TD><code>int8</code></TD></TR>
<TR><TD><code>dbUserFunctionArgument::atBoolean</code></TD><TD><code>u.boolValue</code></TD><TD><code>bool</code></TD></TR>
<TR><TD><code>dbUserFunctionArgument::atString</code></TD><TD><code>u.strValue</code></TD><TD><code>char const*</code></TD></TR>
<TR><TD><code>dbUserFunctionArgument::atReal</code></TD><TD><code>u.realValue</code></TD><TD><code>real8</code></TD></TR>
<TR><TD><code>dbUserFunctionArgument::atReference</code></TD><TD><code>u.oidValue</code></TD><TD><code>oid_t</code></TD></TR>
<TR><TD><code>dbUserFunctionArgument::atRawBinary</code></TD><TD><code>u.rawValue</code></TD><TD><code>void*</code></TD></TR>
</TABLE><P>


For example the following
statements make it possible to use the <code>sin</code> function in SQL
statements:

<PRE>
        #include &lt;math.h&gt;
	...
        USER_FUNC(sin);
</PRE>


Functions can be used only
within the application, where they are defined. Functions are not accessible
from other applications and interactive SQL. If a function returns a string
type , the returned string should be copied by means of the operator
<code>new</code>, because
GigaBASE will call the destructor after copying the returned value.<P>

In GigaBASE, the function argument can (but not necessarily must) be enclosed in 
parentheses. So both of the following expressions are valid:

<PRE>
        '$' + string(abs(x))
	length string y
</PRE><P>

Functions with two argument can be also used as operators. Consider the following example, 
in which function <code>contains</code> which performs case insensitive search for substring is defined:

<PRE>
     bool contains(dbUserFunctionArgument& arg1, dbUserFunctionArgument& arg2) { 
         assert(arg1.type == dbUserFunctionArgument::atString 
	     && arg2.type == dbUserFunctionArgument::atString);
         return stristr(arg1.u.strValue, arg2.u.strValue) != NULL;
     }

     USER_FUNC(contains);
    
     dbQuery q1, q2;
     q1 = "select * from TestTable where name contains 'xyz'";
     q2 = "select * from TestTable where contains(name, 'xyz')";
</PRE>

In this example, queries <code>q1</code> and <code>q2</code> are equivalent.<P>





<H2><A NAME = "cpp">C++ interface</A></H2>
One of the primary goals of GigaBASE is to provide flexible and convenient
application language interface. Anyone who have to use
ODBC or similar SQL interfaces will understand what I am speaking about.
In GigaBASE query can be written in C++ in the following way:<P>

<PRE>
    dbQuery q;
    dbCursor&lt;Contract&gt; contracts;
    dbCursor&lt;Supplier&gt; suppliers;
    int price, quantity;
    q = "(price >=",price,"or quantity >=",quantity,
        ") and delivery.year=1999";
    // input price and quantity values
    if (contracts.select(q) != 0) {
        do {
            printf("%s\n", suppliers.at(contracts->supplier)->company);
        } while (contracts.next());
    }
</PRE>

<H3><A NAME = "table">Table</A></H3>

Data in GigaBASE is stored in tables which corresponds to C++ classes
and class instances - to table records. The following C++ types are accepted
as GigaBASE record atomic components:<P>

<TABLE BORDER ALIGN="center">
<TR><TH>Type</TH><TH>Description</TH></TR>
<TR><TD>bool</TD><TD>boolean type (<code>true,false</code>)</TD></TR>
<TR><TD>int1</TD><TD>one byte signed integer (-128..127)</TD></TR>
<TR><TD>int2</TD><TD>two bytes signed integer (-32768..32767)</TD></TR>
<TR><TD>int4</TD><TD>four bytes signed integer (-2147483648..2147483647)</TD></TR>
<TR><TD>int8</TD><TD>eight bytes signed integer (-2**63..2**63-1)</TD></TR>
<TR><TD>real4</TD><TD>four bytes ANSI floating point type</TD></TR>
<TR><TD>real8</TD><TD>eight bytes ANSI double precision floating point type</TD></TR>
<TR><TD>char const*</TD><TD>zero terminated string</TD></TR>
<TR><TD>dbReference&lt;T&gt;</TD><TD>reference to class T</TD></TR>
<TR><TD>dbArray&lt;T&gt;</TD><TD>dynamic array of elements of type T</TD></TR>
</TABLE><P>

In addition to types specified in the table above, GigaBASE records can
also contain nested structures of these components.
GigaBASE doesn't support unsigned types to simplify query language, eliminate
bugs caused by sign/unsigned comparison and reduce size of database engine.<P>


Unfortunately C++ provides no way
to get metainformation about a class at runtime (RTTI is not supported by all
compilers and also doesn't provide enough information). That is why programmer
has to explicitly enumerate class fields to be included in database table
(it also makes mapping between classes and tables more flexible).
GigaBASE provides a set of macros and classes to make such mapping as simple
as possible.<P>

Each C++ class or structure, which will be used in database, should
contain special method describing its fields. Macro
<code>TYPE_DESCRIPTOR(</code><I>field_list</I><code>)</code> will construct
this method. The single argument of this macro is enclosed in parentheses list
of class fields descriptors. If you want to define some methods for the class
and make them available for database, then macro
<code>CLASS_DESCRIPTOR(</code><I>name, field_list</I><code>)</code>
should be used instead of <code>TYPE_DESCRIPTOR</code>. Class name is needed
to get references to member functions.<P>

The following macros can be used for construction field
descriptors:

<DL>
<DT><B>FIELD(</B>name<B>)</B><DD>Non-indexed field with specified name.
<DT><B>KEY(</B>name, index_type<B>)</B><DD>Indexed field. <I>index_type</I>
should be combination of the following flags:<BR>
<DL>
<DT><code>INDEXED</code>
<DD>When this flag is specified, GigaBASE will create B-tree for the table
using this field as a key. Length of indexed key should not exceed 4Kb. 
<DT><code>HASHED</code> 
<DD>This flag is added only for compatibility with FastDB, but hash
tables are not yet supported by GigaBASE. B-tree index is used instead
of hash table, so using of <code>HASHED</code> is equivalent to using
<code>INDEXED</code> index type. 
<DT><code>CASE_INSENSITIVE</code>
<DD>This flags makes index character case insensitive
(when index search is performed, "aBc", "abc" and "Abc" will be treated as
the same values). This flag affect only for index searches and has no effect for sequential search.
<DT><code>UNIQUE</code> 
<DD>Hint for optimizer that index contains only unique values. 
GigaBASE doesn't enforce unique constraint and this flag is used only to 
optimize query execution plan. 
<DT><code>OPTIMIZE_DUPLICATES</code>
<DD>Hint for optimizer that index contains a lot of duplicates. Without this flag
removing of record which field with restricted set of values is indexed is not efficient
(it requires sequential search among all items with the same key value). 
When this flag is set alternative B-Tree page organization is used which slightly 
decrease find and insert performance, but make remove significantly faster. 
<DT><code>AUTOINCREMENT</code>
<DD>This flag has actually no relation with indices and is included in this mask only to eliminate need in
special macro. This flag is applicable only to fields of <code>int4</code> type and
make GigaBASE to assign unique value to this field when record is inserted in the database. 
</DL>
<DT><B>UDT(</B>name, index_type, comparator<B>)</B><DD>User defined raw binary type. 
Database deals with this type just as with sequence of bytes of specified size.
This field can be used in query (compared with query parameter of the same type), 
may be indexed and used in <code>order by</code> clause. Comparison is performed by means of
<code>comparator</code> function provided by programmer. Comparator functions receives three
arguments: two pointers to the compared raw binary objects and size of binary object.
The semantic of <I>index_type</I> is the same as of <code>KEY</code> macro.
<DT><B>RAWKEY(</B>name, index<B>)</B><DD>Raw binary type with predefined comparator.
This macro is just specialized version of <code>UDT</code> macro with <code>memcmp</code>
used as comparator.
<DT><B>RAWFIELD(</B>name<B>)</B><DD>One more specialization of <code>UDT</code> macro
for raw binary fields with predefined comparator <code>memcmp</code> and without indices.
<DT><B>SUPERCLASS(</B>name<B>)</B><DD>Specifies information about base class
(parent) of the current class.
<DT><B>RELATION(</B>reference, inverse_reference<B>)</B>
<DD>Specifies <I>one-to-one, one-to-many</I> or <I>many-to-many</I>
relationship between classes (tables). Both <I>reference</I>
or <I>inverse_reference</I> fields should have reference or array of reference
types. <code>inverse_reference</code> is field of referenced table
containing inverse reference(s) to the current table. Inverse references
are automatically updated by GigaBASE and also are used for query optimization
(see <A HREF="#inverse">Inverse references</A>).
<DT><B>OWNER(</B>reference, inverse_reference<B>)</B>
<DD>Specifies <I>one-to-many</I> or <I>many-to-many</I>
relationship between classes (tables) of owner-member type.
When owner record is removed all referenced member records are also removed
(cascade delete). If member record has reference to owner class, it should be
declared with RELATION macro.
<DT><B>METHOD(</B>name<B>)</B><DD>Specifies method of the class. Method should
be instance member function, without any parameters and returning
boolean, numeric, reference or string type. Methods should be specified after
all other attributes of the class.
</DL><P>

Although only atomic fields can be indexed, index type can be also specified
for structures. Index will be created for component of the structure
only if such type of index is specified in the index type mask of the
structure. It makes possible to programmers to enable or disable indices for
structure fields depending on the role of the structure in the record.<P>

The following example illustrates creation of type descriptor:<P>

<PRE>
class dbDateTime {
    int4 stamp;
  public:

    int year() {
	return localtime((time_t*)&stamp)-&gt;tm_year + 1900;
    }
    ...

    CLASS_DESCRIPTOR(dbDateTime,
		     (KEY(stamp,INDEXED),
		      METHOD(year), METHOD(month), METHOD(day),
		      METHOD(dayOfYear), METHOD(dayOfWeek),
		      METHOD(hour), METHOD(minute), METHOD(second)));
};

class Detail {
  public:
    char const* name;
    char const* material;
    char const* color;
    real4       weight;

    dbArray&lt; dbReference&lt;Contract&gt; &gt; contracts;

    TYPE_DESCRIPTOR((KEY(name, INDEXED),
		     KEY(material, INDEXED),
		     KEY(color, INDEXED),
		     KEY(weight, INDEXED),
		     RELATION(contracts, detail)));
};

class Contract {
  public:
    dbDateTime            delivery;
    int4                  quantity;
    int8                  price;
    dbReference&lt;Detail&gt;   detail;
    dbReference&lt;Supplier&gt; supplier;

    TYPE_DESCRIPTOR((KEY(delivery, INDEXED),
		     KEY(quantity, INDEXED),
		     KEY(price, INDEXED),
		     RELATION(detail, contracts),
		     RELATION(supplier, contracts)));
};
</PRE>

Type descriptors should be defined for all classes used in database.
In addition to defining type descriptors, it is necessary to establish
mapping between C++ classes and database tables. Macro
<code>REGISTER(</code>name<code>)</code> will do it. Unlike
<code>TYPE_DESCRIPTOR</code>, <code>REGISTER</code> macro should
be used in implementation file and not in header file. It constructs
descriptor of the table associated with the class. If you are going to work
with multiple databases from one application, it is possible to register
table in concrete database by means of
<code>REGISTER_IN(</code>name,database</code<code>)</code> macro.
Parameter <code>database</code> of this macro should be pointer to
<code>dbDatabase</code> object. Below is example of registration tables
in database:<P>

<PRE>
REGISTER(Detail);
REGISTER(Supplier);
REGISTER(Contract);
</PRE>

Table (and correspondent class) can be used only with one database
at each moment of time. When you open database, GigaBASE imports all classes
defined in application in database. If class with the same name already exists
in database, its descriptor stored in the database is compared with
descriptor of this class in application. If there are differences in class
definitions, GigaBASE tries to convert records from the table to new
format. Any kind of conversions between numeric types (integer to
real, real to integer, with extension or truncation, are allowed). Also
addition of new fields can be easily handled. But removing of the fields
is only possible for empty tables (to avoid accidental data destruction).<P>

After loading all class descriptors, GigaBASE checks if all indices specified
in the application class descriptor are already present in database,
constructing new indices and
removing indices, which are no more used. Reformatting of table and
adding/removing indices is only possible when there is no more
than one application accessing database. So when first application is attached
to database, it can perform table conversion. All other application
can only add new classes to database, but not change existed ones.<P>

There is one special preexisted table in database - <code>Metatable</code>,
which contains information about other tables in database. C++ programmer
need not to access this table, because format of database tables is specified
by C++ classes. But in interactive SQL program it is possible to examine
this table to get information about record fields.<P>

Starting from version 2.45 GigaBASE supports autoincrement fields
(fields unique value to which are assigned automaticaly by database).
To be able to use them you should:<P>

<OL>
<LI>Recompile GigaBASE and your application with <code>-DAUTOINCREMENT_SUPPROT</code> flags 
(add this flag to <code>DEFS</code> variables in GigaBASE makefile).<BR>
<B>Attention</B>: database files created by GigaBASE compiled without this option will be incompatible 
with GigaBASE compiled with <code>DAUTOINCREMENT_SUPPORT</code>.

<LI>If you want to use other than 0 initial counter value, you should
asssign value to <code>dbTableDescriptor::initialAutoincrementCount</code>.
It will be shared between all tables, so all table will have the same initial value of 
autoincrement counter.

<LI>Autoincrement fields should be of int4 type and should be declared
with <code>AUTOINCREMENT</code> flag:

<PRE>
        class Record {
             int4 rid;
             char const* name;
             ...
       
             TYPE_DESCRIPTOR((KEY(rid, AUTOINCREMENT|INDEXED), FIELD(name), ...));
       }
</PRE>       
       
<LI>When record with autoincrement field is inserted in the database
there is no need to specify value of autoincremented field (it will be
ignored). After successful insertion of record this field will be
assigned unique value (which is guaranteed to be not used before this
table):

<PRE>
       Record rec;
       // no rec.rid should be specified
       rec.name = "John Smith";
       insert(rec);
       // rec.rid now assigned unique value
       int newRecordId  = rec.rid; // and can be used to reference this record
</PRE>

<LI>When record is removed the value will not be reused.
When transaction is aborted, table autoincrement counter is also rolled back.
</OL><P>


<H3><A NAME = "query">Query</A></H3>
Class query is used for two purposes:

<OL>
<LI>construct query and bind query parameters
<LI>cache compiled queries
</OL>

GigaBASE provides overloaded <code>=</code> and <code>,</code> C++ operators
to construct query statement with parameters. Parameters can be specified
directly in places where they are used, eliminating any mapping between
parameters placeholders and C variables. In the following example of query
pointers to the parameters <code>price</code> and <code>quantity</code>
are stored in the query, so that query can be executed several times
with different values of parameters. C++ overloaded functions make it possible
to automatically determine type of parameter, requiring no extra information
to be supplied by programmer (so programmer has no possibility to make a bug).

<PRE>
        dbQuery q;
        int price, quantity;
        q = "price >=",price,"or quantity >=",quantity;
</PRE>

As far as <code>char*</code> type can be used either for specifying
part of query (such as "price >=") either for parameter of string type,
GigaBASE uses special rule to resolve this ambiguity. This rule is based on the
assumption that there is no reason for splitting query text in two strings
like ("price ",">=") or specifying more than one parameter sequentially
("color=",color,color). So GigaBASE assumes first string to be
part of the query text and switches to <I>operand mode</I>
after it. In <I>operand mode</I> GigaBASE treats <code>char*</code> argument
as query parameter and switches back to query text mode, and so on...
It is also possible not to use this "syntax sugar" and construct
query elements explicitly by <code>dbQuery::append(dbQueryElement::ElementType
type, void const* ptr)</code> method. Before appending elements to the query,
it is necessary to reset query by <code>dbQuery::reset()</code> method
(<code>operator =</code> do it automatically).<P>

It is not to possible use C++ numeric constants as query parameters, because
parameters are accessed by reference. But it is possible to use string
constants, because strings are passed by value. There two possible ways of
specifying string parameters in query: using string buffer or
pointer to pointer to string:<P>

<PRE>
     dbQuery q;
     char* type;
     char name[256];
     q = "name=",name,"and type=",&type;

     scanf("%s", name);
     type = "A";
     cursor.select(q);
     ...
     scanf("%s", name);
     type = "B";
     cursor.select(q);
     ...
</PRE><P>


Query variable can not be passed to a function as parameter or be assigned to
other variable.
When GigaBASE compiles the query, it saves compiled tree in this object.
Next time the query will be used, no compilation is need and ready compiled
tree can be used. It saves some time needed for query compilation.<P>

GigaBASE provides two approaches of integration user-defined types in database.
First - definition of class methods - was already mentioned.
Another approach deals only with query construction. Programmer should
define methods, which will not do actual calculations, but instead
of this returns expression in terms of predefine database types, which
performs necessary calculation. It is better to describe it by example.
GigaBASE has no builtin datetime type. Instead of this normal C++
class <code>dbDateTime</code> can be used by programmer. This class defines
methods allowing to compare two dates using normal relational operators and
specify datetime field in order list:<P>

<PRE>
class dbDateTime {
    int4 stamp;
  public:
    ...
    dbQueryExpression operator == (char const* field) {
	dbQueryExpression expr;
	expr = dbComponent(field,"stamp"),"=",stamp;
	return expr;
    }
    dbQueryExpression operator != (char const* field) {
	dbQueryExpression expr;
	expr = dbComponent(field,"stamp"),"<>",stamp;
	return expr;
    }
    dbQueryExpression operator &lt; (char const* field) {
	dbQueryExpression expr;
	expr = dbComponent(field,"stamp"),">",stamp;
	return expr;
    }
    dbQueryExpression operator &lt;= (char const* field) {
	dbQueryExpression expr;
	expr = dbComponent(field,"stamp"),">=",stamp;
	return expr;
    }
    dbQueryExpression operator &gt; (char const* field) {
	dbQueryExpression expr;
	expr = dbComponent(field,"stamp"),"<",stamp;
	return expr;
    }
    dbQueryExpression operator &gt;= (char const* field) {
	dbQueryExpression expr;
	expr = dbComponent(field,"stamp"),"<=",stamp;
	return expr;
    }
    friend dbQueryExpression between(char const* field, dbDateTime& from,
				     dbDateTime& till)
    {
	dbQueryExpression expr;
	expr=dbComponent(field,"stamp"),"between",from.stamp,"and",till.stamp;
	return expr;
    }

    static dbQueryExpression ascent(char const* field) {
	dbQueryExpression expr;
	expr=dbComponent(field,"stamp");
	return expr;
    }
    static dbQueryExpression descent(char const* field) {
	dbQueryExpression expr;
	expr=dbComponent(field,"stamp"),"desc";
	return expr;
    }
};
</PRE>

All these method receives as their parameter name of the field in the record.
This name is used to contract full name of the records components.
It can be done by class <code>dbComponent</code>, which constructor
takes name the the structure field and name of the component of the structure
and returns compound name separated by '.' symbol.
Class <code>dbQueryExpression</code> is used to collect expression items.
Expression is automatically enclosed in parentheses, eliminating conflicts
with operators precedence.<P>

So, assuming record contains field <code>delivery</code>
of dbDateTime type it is possible
to construct queries like this:

<PRE>
        dbDateTime from, till;
        q1 = between("delivery", from, till),
	     "order by",dbDateTime::ascent("delivery");
        q2 = till &gt;= "delivery";
</PRE>

Except these methods, some class specific method can be also defined
in such way, for example method <code>overlaps</code> for region type.
The benefit of this approach is that database engine will work
with predefined types and is able to apply indices and other optimizations
to proceed such query. And from the other side, encapsulation of class
implementation is preserved, so programmer should not rewrite all queries
when class representation is changed.<P>

Variables of following C++ types can be used as query parameters:<P>

<TABLE BORDER ALIGN="center">
<TR><TD WIDTH=50%>int1</TD><TD WIDTH=50%>bool</TD></TR>
<TR><TD>int2</TD><TD>char const*</TD></TR>
<TR><TD>int4</TD><TD>char **</TD></TR>
<TR><TD>int8</TD><TD>char const**</TD></TR>
<TR><TD>real4</TD><TD>dbReference&lt;T&gt;</TD></TR>
<TR><TD>real8</TD><TD>dbArray&lt; dbReference&lt;T&gt; &gt;</TD></TR>
</TABLE><P>



<H3><A NAME = "cursor">Cursor</A></H3>
Cursors are used to access records returned by select statement.
GigaBASE provides typed cursors, i.e. cursors associated with concrete tables.
There are two kinds of cursors in GigaBASE: readonly cursors and cursors for
update. Cursors in GigaBASE are represented by C++ template class
<code>dbCursor&lt;T&gt;</code>, where <code>T</code> is name of C++ classes
associated with database table. Cursor type should be specified in constructor
of the cursor. By default read-only cursor is created.
To create cursor for update, you should pass parameter
<code>dbCursorForUpdate</code> to the constructor.<P>

Query is executed by cursor <code>select(dbQuery& q)</code>
or <code>select()</code> methods. Last method can be used to iterate through
all records in the table. It is also possible to specify cursor type in select statement:
<code>dbCursorForUpdate</code> or <code>dbCursorViewOnly</code>.
Select methods return number of selected records
and set current position to the first record (if available).
Cursors can be scrolled in forward or backward directions.
Methods <code>next(), prev(), first(), last()</code> can be used to
change current position of the cursor. If operation can not be performed
(no more records available), these methods return <code>NULL</code>
and cursor position is not changed. Method <code>skip(int n)</code> moves cursor 
<code>n</code> positions forward if <code>n</code> is greater than zero, 
or <code>-n</code> positions backward if <code>n</code> is less than zero.
<P>

Cursor for class T contains instance of class T, used for fetching current
record. That is why table classes should have default constructor
(constructor without parameters), which has no side effects.
GigaBASE optimizes fetching records from database, copying only data from
fixed part of the object. String bodies are not copied, instead
of this  correspondent field points directly in database. The same is
true for arrays, which components has the same representation in
database as in application (arrays of scalar types or arrays of nested
structures of scalar components).<P>

Application should not change
elements of strings and arrays in database directly. When array method need
to update array body, it create in-memory copy of the array and updates this
copy. If programmer wants to update string field, it should assign
to the pointer new value, but don't change string directly in database.
It is recommended to use <code>char const*</code> type instead of
<code>char*</code> for string components, to make it possible to compiler to
detect illegal usage of strings.<P>

Cursor class provides <code>get()</code> method for obtaining pointer to
the current record (stored inside cursor). Also overloaded
<code>operator-&gt;</code>
can be used to access components of current record. If cursor is opened
for update, current record can be changed and stored in database
by <code>update()</code> method or can be removed. If current record is
removed, next record becomes current. If there is no next record, then previous
record becomes current (if exists). Method <code>removeAll()</code>
removes all records in the table and method <code>removeAllSelected</code> -
all records selected by the cursor.<P>

When records are updated, database
size can be increased and extension of database section in virtual memory
is needed. As a result of such remapping, base address of the section can be
changed and all pointers to database fields kept by application will become
invalid. GigaBASE automatically updates current records in all opened
cursors when database section is remapped. So, when database is updated,
programmer should access record fields only through the cursors
<code>-&gt;</code> method and do not use pointer variables.<P>

Memory used for the current selection can be released by <code>reset()</code>
method. This method is automatically called by <code>select(),
dbDatabase::commit(), dbDatabase::rollback()</code> methods
and cursor destructor, so in most cases there is no need to
call <code>reset()</code> method explicitly.<P>

Cursors can be also used to access records by reference. Method
<code>at(dbReference&lt;T&gt; const& ref)</code> set cursor to the record
pointed by the reference. In this case selection consists exactly of
one record and <code>next(), prev()</code> methods will always return
<code>NULL</code>. As far as cursors and references in GigaBASE are strictly
typed, all necessary checking can be done statically by compiler and
no dynamic type checking is needed. The only kind of checking,
which is done at runtime, is checking for null reference.
Object identifier of current record in the cursor can be obtained by
<code>currentId()</code> method.<P>

It is possible to restrict number of records returned by select statement.
Cursor has two methods <code>setSelectionLimit(size_t lim)</code> and
<code>unsetSelectionLimit()</code>, which can be used to set/unset limitation
on number of records returned by query. In some situations programmer
wants to receive only one record or only few first records, so query execution
time and size of consumed memory can be reduced by limiting size of
selection. But if you specify order for selected records, query with
restriction for <I>k</I> records will no return first <I>k</I> records
with the smallest value of the key. Instead of this arbitrary <I>k</I>
records will be taken and then sorted.<P>

So all operations with database data are performed by means of cursors. The
only exception is insert operation. GigaBASE provides overloaded insert function:

<PRE>
        template&lt;class T&gt;
        dbReference&lt;T&gt; insert(T const& record);
</PRE>

This function will insert record at the end of the table and return reference
of the created object. Order of insertion is strictly specified in
GigaBASE and applications can use this assumption about records order in the
table. For applications widely using references for navigation between
objects it is necessary to have some <I>root</I> object, from which
traversal by references can be made. Good candidate for such root object
is first record in the table (it is also the oldest record in the
table). This record can be accessed by execution <code>select()</code>
method without parameter. The current record in the cursor will
be the first record in the table.<P>

Starting from version 2.72 GigaBASE provides patch inserts. 
Batch insert dramatically increase speed of database initialization,
for example without batch inserts, inserting first million of records with 2 keys
takes about 460 seconds, inserting second million of records - 18000 seconds (5 hours) !!!
With batch inserts, inserting first million of records takes 95 seconds, and second million - 97 seconds!
Such effect is achieved by delaying reconstruction of indices for inserted records until the transaction 
commit or explicit call of <code>dbDatabase::executeBatch()</code> method. When batch is executed, 
all previously inserted records are sorted by index field and than in this order added to the index. 
Why it allows to significantly increase performance? When database is large (doesn't fit
in page pool) and inserted data contains pseudo-random values, then any insert of record
with indexed fields requires at least one read of B-Tree page from the disk. As
far as average disk access time is about 10ms, we could not insert more than 100 records per second.
But if we first sort inserted data, then most likely  the same pages of B-Tree will 
be used for several subsequent records and number of disk reads is significantly reduced.<P>

Batch inserts are performed by <code>dbDatabase::batchInsert</code> template method
which has the same parameter is <code>insert</code> method. Inserted records will be indexed either when
transaction is committed, either by explicit execution of <code>dbDatabase::executeBatch()</code> method.
<P>

GigaBASE C++ API defines special <code>null</code> variable of reference type.
It is possible to compare <code>null</code> variable with references
or assign it to the reference:<P>

<PRE>
        void update(dbReference&lt;Contract&gt; c) {
            if (c != null) {
	        dbCursor&lt;Contract&gt; contract(dbCursorForUpdate);
		contract.at(c);
		contract-&gt;supplier = null;
            }
        }
</PRE><P>


<A NAME="relative-parameter-binding">
Query parameters usually are bound to C++ variables. In most cases in is convenient and 
flexible mechanism. But in multithreaded application, there is no warranty that the same 
query will not be executed at the same moment of time by another thread with different values
of parameters. One solution is to use synchronization primitives (critical sections or mutexes)
to prevent concurrent execution of the query. But this will lead to performance degradation.
GigaBASE is able to perform read requests in parallel, increasing total system throughput.
The other solution is to use delayed parameter binding. This approach is illustrated by the 
following example:<P>  

<PRE>
dbQuery q;

struct QueryParams { 
    int         salary;
    int         age;
    int         rank;
};

void open()
{
    QueryParams* params = (QueryParams*)NULL;
    q = "salary > ", params->salary, "and age < ", params->age, "and rank =", params->rank;
}

void find(int salary, int age, int rank) 
{ 
    QueryParams params;
    params.salary = salary;
    params.age = age;
    params.rank = rank;
    dbCursor&lt;Person&gt; cusor;
    if (cursor.select(q, &params) &gt; 0) { 
        do { 
	    cout &lt;&lt; cursor->name &lt;&lt; NL;
        } while (cursor.next());
    }
}
</PRE>

So in this example function <code>open</code> binds query parameters just to offsets of 
fields in structure. Later in <code>find</code> functions, actual pointer to the structure
with parameters is passed to the <code>select</code> structure. Function <code>find</code>
can be concurrently executed by several threads and only one compiled version of the query
is used by all these threads. This mechanism is available since version 2.37.<P>
</A>


<H3><A NAME = "database">Database</A></H3>
Class <code>dbDatabase</code> controls interaction of application
with database. It performs synchronization of concurrent accesses to the
database, transaction management, memory allocation, error handling,...<P>

Constructor of <code>dbDatabase</code> objects allows programmer to specify
some database parameters:

<PRE>
    dbDatabase(dbAccessType type = dbAllAccess,
	       size_t poolSize = 0, // autodetect size of available memory
	       size_t dbExtensionQuantum = dbDefaultExtensionQuantum,
	       size_t dbInitIndexSize = dbDefaultInitIndexSize,
	       int nThreads = 1);
</PRE>

Database can be opened in readonly mode (<code>dbDatabase::dbReadOnly</code>
access type) or in normal mode allowing modification of database
(<code>dbDatabase::dbAllAccess</code>). When database is opened in readonly
mode, no new class definitions  can be added to database and also definition
of existed class and indices can not be altered.<P>

Parameter <code>poolSize</code> specifies number of pages in page pool used
to optimize file IO. GigaBASE is using 8Kb pages. Size of pool should
not be larger than amount of physical memory at the computer and moreover some
amount of memory should be reserved for operating system and other application
data structures. When default value 0 of this parameter is used, GigaBASE will
automatically select page pool size using information about available physical
memory in the system. Current algorithm of page pool size calculation
is the following (it is the subject for change in future):
GigaBASE uses maximal number which is power of two and less than amount of
physical memory in the system unless difference of total amount of
available physical memory and this number is greater than some unused memory
threshold (currently 64Mb). If the difference is greater than threshold value,
then size of pool is taken as size of available physical memory minus
threshold.<P>

Parameter <code>dbExtensionQuantum</code> specifies quantum of extension of
memory allocation bitmap.
Briefly speaking, value of this parameters specifies how much memory
will be allocated sequentially without attempt to reuse space of
deallocated objects. Default value of this parameter is 16 Mb.
See section <A HREF="#memory">Memory allocation</A> for more details.<P>

Parameter <code>dbInitIndexSize</code> specifies initial index size.
All objects in GigaBASE are accessed through object index.
There are two copies
of object index: current and committed. Object indices are reallocated on
demand and setting initial index size can only reduce (or increase)
number of reallocations. Default value of this parameter is 64K object
identifiers.<P>

And the last parameter <code>nThreads</code> controls level of query
parallelization. If it is greater than 1, then GigaBASE can start parallel
execution of some queries (including sorting of result). Specified number of
parallel threads will be spawned by GigaBASE engine in this case. Usually
there is no sense to specify the value of this parameter greater than
number of online CPUs in the system. It is also possible to pass
zero as value of the parameter, in this case GigaBASE will automatically detect
number of online CPUs in the system. Number of threads can be also set
by <code>dbDatabase::setConcurrency</code> method at any moment of time.<P>

Class <code>dbDatabase</code> contains static field
<code>dbParallelScanThreshold</code>, which specifies threshold for
number of records records in the table after which query parallelization
is used. Default value of this parameter is 1000.<P>

Database can be opened by <code>open(char const* fileName = NULL)</code>
method. Unlike FastDB, GigaBASE is not needed in database name and only file
name should be specified. No any suffixes are implicitly appended to database
file name. This is the only difference in interfaces to FastDB and GigaBASE.
<P>

As far as some operating systems have limitations for maximal file size,
GigaBASE provides way to split one logical data file into several physical
segments (operating systems files). Segments can be located at different
partitions and file systems. Such file is called in GigaBASE
<I>multifile</I>. To create multifile you should specify <code>@</code>
symbol before database file name. In this case GigaBASE will treat this name
as name of the file with multifile segments description. Each line of this file
(except last) should contain name of the operating system file
(or raw partition)
corresponds to the multifile segment and size (in 8Kb pages)
of the segment.
Only the last segment of the multifile can by dynamically extended when
database is grown. That is why it is not necessary to specify size
of the last segment, so last line should contain only the name of the file.<P>

It is possible to specify offset from the beginning of the file (it can be
useful for raw partitions). Offset should be specified as the suffix of the file
name in [] brackets without any spaces between, for example: <code>"/dev/hda0[512]"</code>. Unlike size of segment, offset is specified in bytes, not in pages.<P>

Below is the example of multifile description file consisting of two
segments represented by physical disk partitions, first of which has size 4Gb:

<PRE>
/dev/hdb1 524288
/dev/hdc1
</PRE><P>

It is also possible to increase performance by balancing disk load. The idea is the same as with 
multifile - split the database file into several parts, placed at different disk controllers. 
But unlike multifile approach, blocks are cyclically distributed among disks - first block at first disk, 
second block at second disk, ... n-th block at n-disk, n+1 block at 1 disk,... The size of block is 
currently set to one megabyte (it can be changed with
<PRE>
    <code>.RaidBlockSize BLOCK_SIZE</code>
</PRE>
line in description file. The partitions of raid file are specified in the same way as for 
multifile - one partition name per line, but no size of segment should be specified (so if no 
segment size was specified, then GigaBASE will create RAID file, otherwise - multifile).
Offset within partition can be specified in the same way as for multifile<P>



Method&nbsp;<code>open</code> returns <code>true</code> if database was
successfully opened or <code>false</code> if open operation failed.
In last case database <code>handleError</code> method is called with
<code>DatabaseOpenError</code> error code. Database session can be terminated
by <code>close</code> method, which implicitly commits current transaction.<P>

In multithreaded application each thread, which wants to access database,
should first be attached to it. Method <code>dbDatabase::attach()</code>
allocates thread specific data and attaches thread to the database.
This method is automatically called by <code>open()</code> method, so
there is no reason to call <code>attach()</code> method for the thread
opening database. When thread finishes work with database, it should
call <code>dbDatabase::detach()</code> method. Method
<code>close</code> automatically invokes <code>detach()</code> method.
Method <code>detach()</code> implicitly commits current transaction.
Attempt to access database by detached thread causes assertion failure.<P>

GigaBASE is able to perform compilation and execution of queries in parallel,
providing significant increase of performance in multiprocessor systems.
But concurrent updates of database are not possible (this is a price
for efficient log-less transaction mechanism and zero time recovery).
When application wants to modify database (open cursor for update or
insert new record in the table), it first locks database in exclusive mode,
prohibiting accesses to database by other applications, even for
read-only queries. So to avoid blocking of database application for a long
time, modification transactions should be done as short as possible.
No blocking operations (like waiting input from the user) should be
done within transaction.<P>

Using only shared and exclusive locks on database
level, allows GigaBASE to almost eliminate overhead of locking and
optimize speed of execution of non-conflicting operations. But if many
applications simultaneously updates different parts of database, then
approach used in GigaBASE will be very inefficient.
That is why GigaBASE is most
suitable for single-application database access model or for
multiple applications with read-dominated access pattern model.<P>

Cursor object should be used only by one thread in a multithreaded application. 
If there are more than one threads in your
applications, use local variables for cursors
in each thread. It is possible to share query variables between threads, but take care about
query parameters. The query should either has no parameters, or 
<A HREF="#relative-parameter-binding">relative form</A> of parameters
binding should be used.<P>

The <code>dbDatabase</code> object is shared between all
threads and uses thread specific data to perform query
compilation and execution in parallel with minimal synchronization overhead.
There are few global things, which require synchronization: symbol table,
pool of tree node,... But scanning, parsing and execution of query can
be done without any synchronization, providing high level of concurrency
at multiprocessor systems.<P>

Database transaction is started by first select or insert operation.
If cursor for update is used, then database is locked in exclusive
mode, prohibiting access to the database by other applications and threads.
If read-only cursor is used, then database is locked in shared mode preventing
other application and threads from modifying database, but allowing concurrent
read requests execution. Transaction should be explicitly terminated
either by <code>dbDatabase::commit()</code> method, which fixes all
changes done by transaction in database, or by
<code>dbDatabase::rollback()</code> method which undo all modifications
done by transaction. Method <code>dbDatabase::close()</code> automatically
commits current transaction.<P>

If several threads are concurrently updating database, it will be possible
to increase total performance by using partial transaction commit.
Method <code>dbDatabase::precommit()</code> doesn't flush any changes to the
disk and switch object index. Instead of this it only release locks hold by
transaction allowing other threads to proceed. All cursors opened by the thread
are closed by <code>dbDatabase::precommit()</code> method. When the thread will
access the database next time, it will have to obtain database locks once
again. Using <code>precommit</code> method instead of <code>commit</code>
eliminates disk operations and so dramatically increases performance. But it
is necessary to remember that if application or system fault will take place
after <code>precommit</code> method execution, all changes made by transaction
will be lost.<P>

If you start transaction by performing selection using read-only cursor and
then use cursor for update to perform some modifications of database,
database will be first locked in shared mode and then lock will be upgraded
to exclusive. This can cause deadlock problem if database is simultaneously
accessed by several applications. Imagine that application A starts
read transaction and application B also starts read transaction. Both
of them hold shared locks on the database. If both of them wants to
upgrade their locks to exclusive, they will forever block each other
(exclusive lock can not be granted until shared lock of other process exists).
To avoid such situation try to use cursor for update at the beginning of
transaction or explicitly use <code>dbdatabase::lock()</code> method.
More information about implementation of transactions in GigaBASE can be found
in section <A HREF="#transaction">Transactions</A>.<P>

It is possible to explicitly lock database by <code>lock()</code> method.
Locking is usually done automatically and there are few cases when
you will want to use this method. It will lock database in exclusive
mode until the end of current transaction.<P>

Backup of database can be done by the following method:

<PRE>
        bool dbDatabase::backup(char const* backupFileName);
</PRE>

Backup locks database in shared mode and flush image of database
in main memory to specified file. Because of using of shadow object index,
database file is always in consistent state, so recovery from the backup can
be performed just by renaming backup file (if backup was performed on tape, it
should be first restored to the disk). If multifile was used as database
storage, then simple renaming or copying of backup file is not possible.
GigaBASE provides restore method:

<PRE>
        bool dbDatabase::restore(char const* backupFileName,
                                 const* databaseFileName);
</PRE>

This method should be called before opening database, restore of
online database is not possible. If <code>databaseFileName</code>
contains <code>@</code> in first position, the rest of the name is treated
as the name of the file with multifile segments description (the same as
used by <code>dbDatabase::open</code> method). Database can be also restored
using <code>restore</code> code of <B>subsql</B> utility.<P>

Class <code>dbDatabase</code> is also responsible for handling various
application errors, such as syntax errors in query compilation,
out of range index or null reference access during query execution.
There is virtual method <code>dbDatabase::handleError</code>, which handles
these errors:


<PRE>
        virtual void handleError(dbErrorClass error,
                                 char const*  msg = NULL,
                                 int          arg = 0);
</PRE>

Programmer can derive his own subclass from <code>dbDatabase</code>
class and redefine default reaction on errors.<P>




<TABLE BORDER ALIGN="center">
<CAPTION>Error classes and default handling</CAPTION>
<TR><TH>Class</TH><TH>Description</TH><TH>Argument</TH><TH>Default reaction</TH></TR>
<TR><TD>QueryError</TD><TD>query compilation error</TD><TD>position in query string</TD><TD>abort compilation</TD></TR>
<TR><TD>ArithmeticError</TD><TD>arithmetic error during division or power operations</TD><TD ALIGN="center">-</TD><TD>terminate application</TD></TR>
<TR><TD>IndexOutOfRangeError</TD><TD>index is out if array bounds</TD><TD>value of index</TD><TD>terminate application</TD></TR>
<TR><TD>DatabaseOpenError</TD><TD>error while database opening</TD><TD ALIGN="center">-</TD><TD>open method will return <code>false</code></TD></TR>
<TR><TD>FileError</TD><TD>failure of file IO operation</TD><TD>error code</TD><TD>terminate application</TD></TR>
<TR><TD>OutOfMemoryError</TD><TD>not enough memory for object allocation</TD><TD>requested allocation size</TD><TD>terminate application</TD></TR>
<TR><TD>Deadlock</TD><TD>upgrading lock cause deadlock</TD><TD ALIGN="center">-</TD><TD>terminate application</TD></TR>
<TR><TD>NullReferenceError</TD><TD>null reference is accessed during query execution<TD ALIGN="center">-</TD><TD>terminate application</TD></TR>
</TABLE><P>


<H2><A NAME = "cli">Call level interface</A></H2>

Interface described in previous section provides convenient and reliable mechanism for
accessing data from C++. It has two drawbacks:

<OL>
<LI>It is very C++ specific and can not be used with other programming languages
<LI>It is suitable only for local connections to the database (within one system).
</OL>

Interface described below outcomes these two restrictions. It consists of the set of
pure ANSI C functions and using it mapping of any programming language to the GigaBASE
database can be easily implemented. Connection between client and serves is performed by
sockets (either local, either standard TCP/IP sockets). Certainly this interface is
less convenient and more error prone than C++ interface, but this is a cost of its
flexibility. All types, constants and functions are declared in <A HREF="cli.h">cli.h</A>
file.<P>

GigaBASE provides multithreaded server for handling client CLI sessions. This server can be
started from <A HREF="#subsql">SubSQL</A> utility by
<code>start server 'HOST:PORT' &lt;number-of-threads&gt;</code> command.
This server will accept local (within one system) and global clients connections and
attach one thread from the threads pool to each connection. The size of thread's pool
is controlled by <i>number-of-threads</i> parameters. But the server can spawn more
than specified number of threads if there are many active connections. A thread is attached
to the client until the end of the session. If session is abnormally terminated, all
changes made by the client are rollbacked. The server can be stopped by correspondent
<code>stop server 'HOST:PORT'</code> command.<P>

Gigabase CLI API also optionally supports authentication. To enable it, you should recompile
GigaBASE with <code>SECURE_SERVER</code> macro defined. When this macro is defined, 
the table <code>UserInfo</code> is created at server. <code>cli_open</code> method takes
<code>user_name</code> and <code>password</code> parameters which are passed to the server.
When connection is established, server searches in <code>UserInfo</code> table for the user with 
specified name and password. If the user is not found or password doesn't match, the server returns
<code>cli_login_failed</code> code to the client. To enter new user or remove old one, database 
administrator can use SubSQL insert and remove commands. As far as update command is not currently 
implemented, you will have to perform remove and insert if you what to change users password.
Do not forget to commit your changes, otherwise all clients will be blocked.<P>


<A NAME="cli_errors">
<TABLE><CAPTION><FONT SIZE=+1><B><U>CLI functions return codes</U></B></FONT></CAPTION>
<TR><TH>Error code</TH><TH>Description</TH></TR>
<TR><TD>cli_ok</TD><TD>Successful completion</TD></TR>
<TR><TD>cli_bad_address</TD><TD>Invalid format of server URL</TD></TR>
<TR><TD>cli_connection_refused</TD><TD>Connection with server could not be established</TD></TR>
<TR><TD>cli_bad_statement</TD><TD>Text of SQL statement is not correct</TD></TR>
<TR><TD>cli_parameter_not_found</TD><TD>Parameter was not found in statement</TD></TR>
<TR><TD>cli_unbound_parameter</TD><TD>Parameter was not specified</TD></TR>
<TR><TD>cli_column_not_found</TD><TD>No such column in the table</TD></TR>
<TR><TD>cli_incompatible_type</TD><TD>Conversion between application and database type is not possible</TD></TR>
<TR><TD>cli_network_error</TD><TD>Connection with server is broken</TD></TR>
<TR><TD>cli_runtime_error</TD><TD>Error during query execution</TD></TR>
<TR><TD>cli_bad_descriptor</TD><TD>Invalid statement/session description</TD></TR>
<TR><TD>cli_unsupported_type</TD><TD>Unsupported type for parameter or column</TD></TR>
<TR><TD>cli_not_found</TD><TD>Record was not found</TD></TR>
<TR><TD>cli_not_update_mode</TD><TD>Attempt to update records selected by view only cursor</TD></TR>
<TR><TD>cli_table_not_found</TD><TD>There is no table with specified name in the database</TD></TR>
<TR><TD>cli_not_all_columns_specified</TD><TD>Insert statement doesn't specify values for all table columns</TD></TR>
<TR><TD>cli_not_fetched</TD><TD><A HREF="#cli_fetch"><code>cli_fetch</code></A> method was not called</TD></TR>
<TR><TD>cli_already_updated</TD><TD><A HREF="#cli_update"><code>cli_update</code></A> method was invoked more than once for the same record</TD></TR>
<TR><TD>cli_login_failed</TD><TD>Login to the server is failed</TD></TR>
<TR><TD>cli_empty_parameter</TD><TD>Parameter is not assigned a value</TD></TR>
<TR><TD>cli_closed_connection</TD><TD>Access to the closed connection</TD></TR>
<TR><TD>cli_table_already_exists</TD><TD>Attempt to create existed table</TD></TR>
<TR><TD>cli_not_implemented</TD><TD>Function is not implemented</TD></TR>
</TABLE></A>

<P>

<A NAME = "cli_types">
<TABLE><CAPTION><FONT SIZE=+1><B><U>Supported types</U></B></FONT></CAPTION>
<TR><TH>Type</TH><TH>Description</TH><TH>Size</TH></TR>
<TR><TD>cli_oid</TD><TD>Object identifier</TD><TD>4</TD></TR>
<TR><TD>cli_bool</TD><TD>Boolean type</TD><TD>1</TD></TR>
<TR><TD>cli_int1</TD><TD>Tiny integer type</TD><TD>1</TD></TR>
<TR><TD>cli_int2</TD><TD>Small integer type</TD><TD>2</TD></TR>
<TR><TD>cli_int4</TD><TD>Integer type</TD><TD>4</TD></TR>
<TR><TD>cli_int8</TD><TD>Big integer type</TD><TD>8</TD></TR>
<TR><TD>cli_real4</TD><TD>Single precision floating point type</TD><TD>4</TD></TR>
<TR><TD>cli_real8</TD><TD>Double precision floating point type</TD><TD>8</TD></TR>
<TR><TD>cli_decimal</TD><TD>Decimal numeric type (number is represented as zero terminated ASCII string)</TD><TD>1*N</TD></<TR>
<TR><TD>cli_asciiz</TD><TD>Zero terminated string of bytes</TD><TD>sizeof(char_t)*N</TD></TR>
<TR><TD>cli_pasciiz</TD><TD>Pointer to zero terminated string (pointer should be initialized by application)</TD><TD>sizeof(char_t)*N</TD></TR>
<TR><TD>cli_cstring</TD><TD>String with counter (see declaration of cli_ctring_t in cli.h). The terminated null character is not stored. When cli_cstring is used as fetched column type, the pointer is set to the internal buffer, so no memory should be allocated and deallocated to hold value.</TD><TD>8</TD></TR>
<TR><TD>cli_array_of_oid</TD><TD>Array of references</TD><TD>4*N</TD></TR>
<TR><TD>cli_array_of_bool</TD><TD>Array of booleans</TD><TD>1*N</TD></TR>
<TR><TD>cli_array_of_int1</TD><TD>Array of tiny integers</TD><TD>1*N</TD></TR>
<TR><TD>cli_array_of_int2</TD><TD>Array of small integers</TD><TD>2*N</TD></TR>
<TR><TD>cli_array_of_int4</TD><TD>Array of integers</TD><TD>4*N</TD></TR>
<TR><TD>cli_array_of_int8</TD><TD>Array of big integers</TD><TD>8*N</TD></TR>
<TR><TD>cli_array_of_real4</TD><TD>Array of reals</TD><TD>4*N</TD></TR>
<TR><TD>cli_array_of_real8</TD><TD>Array of long reals</TD><TD>8*N</TD></TR>
<TR><TD>cli_any</TD><TD>can be used only for binding columns, server will use the same type for column as stored in the database</TD><TD>?</TD></TR>
<TR><TD>cli_datetime</TD><TD>time in seconds since 00:00:00 UTC, January 1, 1970.</TD><TD>4  </TD></TR>
<TR><TD>cli_autoincrement</TD><TD>column automatically assigned value during record insert</TD><TD>4</TD></TR>
<TR><TD>cli_rectangle</TD><TD>rectangle (by default R2 rectangle with int4 coordinates</TD><TD>dimension*2*sizeof(cli_coord_t)</TD></TR>
</TABLE></A><P>

<HR>

<A NAME = "cli_open"><pre>
int cli_open(char const*   server_url,
	     int           max_connect_attempts,
	     int           reconnect_timeout_sec,
	     char_t const* user_name,
	     char_t const* password,
	     int           pooled_connection);
</pre></A>
<DL><DD>
Establish connection with the server
<DL>
<DT><B>Parameters</B>
<DD><code>server_url</code> - zero terminated string with server address and port,
for example "localhost:5101" or "195.239.208.240:6100". It can contain multiple addresses, in this case
<i>replication socket</i> will be created. Data written to such socket will be broadcasted to all specified servers.
And read from this socket cause receiving response from each server and checking that them are equal. 
If connection with one of the server is broken or response received from this server is not equal to other
responses, then this server is excluded from list of available servers. Client can continue work with database until
at least one server is available and it is possible to choose correct response (quorum is achieved).
<DD><code>max_connect_attempts</code>  - number of attempts to establish connection
<DD><code>reconnect_timeout_sec</code> - timeout in seconds between connection attempts
<DD><code>reconnect_timeout_sec</code> - timeout in seconds between connection attempts
<DD><code>user_name</code> - user name for login
<DD><code>password</code> - password for login
<DD><code>pooled_connection</code> - if not 0, then connection will be allocated from the connection pool
<DT><B>Returns</B>
<DD><code>&gt;= 0</code> - connection descriptor to be used in all other cli calls
<DD><code>&lt;  0</code> - error code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_close"><pre>
int cli_close(int session);
</pre></A>
<DL><DD>
Close session. If session was opened with pooled connections enabled, it is not actually closed, 
but placed in the pool of connection and can be reused ni future.
<DL>
<DT><B>Parameters</B>
<DD><code>session</code> - session descriptor returned by <A HREF="#cli_open"><code>cli_open</code></A>
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_clear_connection_pool"><pre>
void cli_clear_connection_pool();
</pre></A>
<DL><DD>
Close all released connection in connection pool.
</DL>

<HR>

<A NAME = "cli_statement"><pre>
int cli_statement(int session, char const* stmt);
</pre></A>
<DL><DD>
Specify SubSQL statement to be executed at server.
Binding to the parameters and columns can be established.
<DL>
<DT><B>Parameters</B>
<DD><code>session</code> - session descriptor returned by <A HREF="#cli_open"><code>cli_open</code></A>
<DD><code>stmt</code>    - zero terminated string with SubSQL statement
<DT><B>Returns</B>
<DD><code>&gt;= 0</code> - statement descriptor
<DD><code>&lt;  0</code> - error code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_parameter"><pre>
int cli_parameter(int         statement,
		  char const* param_name,
		  int         var_type,
		  void*       var_ptr);
</pre></A>
<DL><DD>
Bind parameter to the statement
<DL>
<DT><B>Parameters</B>
<DD><code>statement</code>  - statement descriptor returned by <A HREF="#cli_statement"><code>cli_statement</code></A>
<DD><code>param_name</code> - zero terminated string with parameter name.
Parameter name should start with '%'
<DD><code>var_type</code>   - type of variable as described in cli_var_type enum.
Only scalar and zero terminated string types are supported.
<DD><code>var_ptr</code>  - pointer to the variable
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_column"><pre>
int cli_column(int         statement,
	       char const* column_name,
	       int         var_type,
	       int*        var_len,
	       void*       var_ptr);
</pre></A>
<DL><DD>
Bind extracted column of select or insert statement
<DL>
<DT><B>Parameters</B>
<DD><code>statement</code> - statement descriptor returned by <A HREF="#cli_statement"><code>cli_statement</code></A>
<DD><code>column_name</code> - zero terminated string with column name
<DD><code>var_type</code> - type of variable as described in cli_var_type enum
<DD><code>var_len</code> - pointer to the variable to hold length of array variable.
This variable should be assigned the maximal length of the array/string buffer,
pointed by <code>var_ptr</code>. After the execution of the statement it is assigned the
real length of the fetched array/string. If it is large than length of the buffer,
then only part of the array will be placed in the buffer, but <code>var_len</code>
still will contain the actual array length.
<DD><code>var_ptr</code> - pointer to the variable
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_array_column"><pre>
typedef void* (*cli_column_set)(int var_type, void* var_ptr, int len);
typedef void* (*cli_column_get)(int var_type, void* var_ptr, int* len);

int cli_array_column(int            statement,
		     char const*    column_name,
		     int            var_type,
		     void*          var_ptr,
		     cli_column_set set,
		     cli_column_get get);
</pre></A>
<DL><DD>
Specify get/set functions for the array column
<DL>
<DT><B>Parameters</B>
<DD><code>statement</code> - statement descriptor returned by <A HREF="#cli_statement"><code>cli_statement</code></A>
<DD><code>column_name</code> - zero terminated string with column name
<DD><code>var_type</code> - type of variable as described in cli_var_type enum
<DD><code>var_ptr</code> - pointer to the variable
<DD><code>set</code> - function which will be called to construct fetched field.
It receives pointer to the variable, length of the fetched array and returns pointer
to the array's elements.
<DD><code>get</code> - function which will be called to update the field in the
database. Given pointer to the variable, it should return pointer to the array elements
and store length of the array to the variable pointer by len parameter
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_array_column_ex"><pre>
typedef void* (*cli_column_set_ex)(int var_type, void* var_ptr, int len, 
				   char const* column_name, int statement, void const* data_ptr);
typedef void* (*cli_column_get_ex)(int var_type, void* var_ptr, int* len, 
				   char const* column_name, int statemen);

int cli_array_column(int               statement,
		     char const*       column_name, 
		     int               var_type,
		     void*             var_ptr,
		     cli_column_set_ex set,
		     cli_column_get_ex get);
</pre></A>
<DL><DD>
Specify extended get/set functions for the array column
<DL>
<DT><B>Parameters</B>
<DD><code>statement</code> - statememt descriptor returned by <A HREF="#cli_statement"><code>cli_statement</code></A>
<DD><code>column_name</code> - zero terminated string with column name  
<DD><code>var_type</code> - type of variable as described in cli_var_type enum
<DD><code>var_ptr</code> - pointer to the variable
<DD><code>set</code> - function which will be called to construct fetched field. 
It receives type of the vartiable, pointer to the variable, length of the fetched array, name of the fetched column,
statement descriptor and pointer to the array data. If this method returns not NULL pointer, 
database will copy unpacked array to the returned location. Otherwise it is assumed that
function handle data itself.
<DD><code>get</code> - function which will be called to update the field in the 
database. Given type of the vartiable, pointer to the variable, column name and statment descriptor,
it should return pointer to the array elements and store length of the array to the variable pointer by len parameter
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>


<A NAME = "cli_fetch"><pre>
enum {
    cli_view_only,
    cli_for_update
};

int cli_fetch(int statement, int for_update);
</pre></A>
<DL><DD>
Execute select statement.
<DL>
<DT><B>Parameters</B>
<DD><code>statement</code> - statement descriptor returned by <A HREF="#cli_statement"><code>cli_statement</code></A>
<DD><code>for_update</code> - not zero if fetched rows will be updated
<DT><B>Returns</B>
<DD><code>&gt;= 0</code> - success, for select statements number of fetched rows is returned
<DD><code>&lt;  0</code> - error code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_insert"><pre>
int cli_insert(int statement, cli_oid_t* oid);
</pre></A>
<DL><DD>
Execute insert statement.
<DL>
<DT><B>Parameters</B>
<DD><code>statement</code> - statement descriptor returned by <A HREF="#cli_statement"><code>cli_statement</code></A>
<DD><code>oid</code> - object identifier of created record.
<DT><B>Returns</B>
<DD>status code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>


<A NAME = "cli_get_first"><pre>
int cli_get_first(int statement);
</pre></A>
<DL><DD>
Get first row of the selection.
<DL>
<DT><B>Parameters</B>
<DD><code>statement</code> - statement descriptor returned by <A HREF="#cli_statement"><code>cli_statement</code></A>
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>


<A NAME = "cli_get_last"><pre>
int cli_get_last(int statement);
</pre></A>
<DL><DD>
Get last row of the selection.
<DL>
<DT><B>Parameters</B>
<DD><code>statement</code> - statement descriptor returned by <A HREF="#cli_statement"><code>cli_statement</code></A>
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>


<A NAME = "cli_get_next"><pre>
int cli_get_next(int statement);
</pre></A>
<DL><DD>
Get next row of the selection. If get_next records is called exactly after
<A HREF="#cli_fetch"><code>cli_fetch</code></A> function call, is will fetch the first record in selection.
<DL>
<DT><B>Parameters</B>
<DD><code>statement</code> - statement descriptor returned by <A HREF="#cli_statement"><code>cli_statement</code></A>
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>


<A NAME = "cli_get_prev"><pre>
int cli_get_prev(int statement);
</pre></A>
<DL><DD>
Get previous row of the selection. If get_next records is called exactly after
<A HREF="#cli_fetch"><code>cli_fetch</code></A> function call, is will fetch the last record  in selection.
<DL>
<DT><B>Parameters</B>
<DD><code>statement</code> - statement descriptor returned by <A HREF="#cli_statement"><code>cli_statement</code></A>
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>


<A NAME = "cli_get_oid"><pre>
cli_oid_t cli_get_oid(int statement);
</pre></A>
<DL><DD>
Get object identifier of the current record
<DL>
<DT><B>Parameters</B>
<DD><code>statement</code> - statement descriptor returned by <A HREF="#cli_statement"><code>cli_statement</code></A>
<DT><B>Returns</B>
<DD>object identifier or 0 if no object is selected
</DL></DL>

<HR>


<A NAME = "cli_update"><pre>
int cli_update(int statement);
</pre></A>
<DL><DD>
Update the current row in the selection. You have to set
for_update parameter of <A HREF="#cli_fetch"><code>cli_fetch</code></A> to 1 in order to be able
to perform updates. Updated value of row fields will be taken
from bound column variables.
<DL>
<DT><B>Parameters</B>
<DD><code>statement</code> - statement descriptor returned by <A HREF="#cli_statement"><code>cli_statement</code></A>
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>


<A NAME = "cli_remove"><pre>
int cli_remove(int statement);
</pre></A>
<DL><DD>
Remove all selected records. You have to set <code>for_update</code> parameter of
<A HREF="#cli_fetch"><code>cli_fetch</code></A> to 1 in order to be able to remove records.
<DL>
<DT><B>Parameters</B>
<DD><code>statement</code> - statement descriptor returned by <A HREF="#cli_statement"><code>cli_statement</code></A>
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_free"><pre>
int cli_free(int statement);
</pre></A>
<DL><DD>
Deallocate statement and all associated data
<DL>
<DT><B>Parameters</B>
<DD><code>statement</code> - statement descriptor returned by <A HREF="#cli_statement"><code>cli_statement</code></A>
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_commit"><pre>
int cli_commit(int session);
</pre></A>
<DL><DD>
Commit current database transaction
<DL>
<DT><B>Parameters</B>
<DD><code>session</code> - session descriptor as returned by <A HREF="#cli_open"><code>cli_open</code></A>
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_abort"><pre>
int cli_abort(int session);
</pre></A>
<DL><DD>
Abort current database transaction
<DL>
<DT><B>Parameters</B>
<DD><code>session</code> - session descriptor as returned by <A HREF="#cli_open"><code>cli_open</code></A>
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_show_tables"><pre>
int cli_show_tables(int session, cli_table_descriptor** tables);
</pre></A>
<DL><DD>
Return list of table presetn in the database.
<PRE> 
        typedef struct cli_table_descriptor {
            char const*       name;
        } cli_table_descriptor;
</PRE>
<DL>
<DT><B>Parameters</B>
<DD><code>session</code> - session descriptor as returned by <A HREF="#cli_open"><code>cli_open</code></A>
<DD><code>tables</code> - address of the pointer to the array with table descriptors. 
<code>cli_show_tables</code> uses malloc to allocate this array, and it should be deallocated by application using free() function.
<DT><B>Returns</B>
<DD><code>&gt;= 0</code> - number of tables in the database (Metatable is not returned/counted)
<DD><code>&lt;  0</code> - error code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_describe"><pre>
int cli_describe(int session, char const* table, cli_field_descriptor** fields);
</pre></A>
<DL><DD>
Return definition of fields of specified table. Definition of field descriptor has the following format:
<PRE> 
        typedef struct cli_field_descriptor {  
            enum cli_var_type type;
            int               flags;
            char_t const*     name;
            char_t const*     refTableName;
            char_t const*     inverseRefFieldName;
        } cli_field_descriptor;
</PRE>
<DL>
<DT><B>Parameters</B>
<DD><code>session</code> - session descriptor as returned by <A HREF="#cli_open"><code>cli_open</code></A>
<DD><code>table</code> - name of the table
<DD><code>fields</code> - address of the pointer to the array with field descriptors. <code>cli_describe</code> uses malloc to allocate this array, and it should be deallocated by application using free() function.
<DT><B>Returns</B>
<DD><code>&gt;= 0</code> - number of fields in the table
<DD><code>&lt;  0</code> - error code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<HR>

<A NAME = "cli_create_table"><pre>
int cli_create_table(int                   session, 
                     char_t const*         tableName, 
                     int                   nFields, 
		     cli_field_descriptor* fields);
</pre></A>
<DL><DD>
Create new table
<DL>
<DT><B>Parameters</B>
<DD><code>session</code> - session descriptor as returned by <A HREF="#cli_open"><code>cli_open</code></A>
<DD><code>tableName</code> - name of the created table
<DD><code>nFields</code> - number of columns in the table
<DD><code>fields</code> - array with table columns descriptors. Descriptor is has the following structure:
<PRE>
    enum cli_field_flags { 
        cli_hashed           = 1, /* field should be indexed usnig hash table */
        cli_indexed          = 2, /* field should be indexed using B-Tree */
        cli_case_insensitive = 4  /* index is case insensitive */
    };

    typedef struct cli_field_descriptor { 
        enum cli_var_type type;
        int               flags;
        char_t const*     name;
        char_t const*     refTableName;
        char_t const*     inverseRefFieldName;
    } cli_field_descriptor;
</PRE>
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>


<HR>

<A NAME = "cli_alter_table"><pre>
int cli_alter_table(int                   session, 
                     char_t const*         tableName, 
                     int                   nFields, 
		     cli_field_descriptor* fields);
</pre></A>
<DL><DD>
Change format of existed table
<DL>
<DT><B>Parameters</B>
<DD><code>session</code> - session descriptor as returned by <A HREF="#cli_open"><code>cli_open</code></A>
<DD><code>tableName</code> - name of the altered table
<DD><code>nFields</code> - number of columns in the table
<DD><code>fields</code> - array with table columns descriptors. Descriptor is has the following structure:
<PRE>
    enum cli_field_flags { 
        cli_hashed           = 1, /* field should be indexed usnig hash table */
        cli_indexed          = 2, /* field should be indexed using B-Tree */
        cli_case_insensitive = 4  /* index is case insensitive */
    };

    typedef struct cli_field_descriptor { 
        enum cli_var_type type;
        int               flags;
        char_t const*     name;
        char_t const*     refTableName;
        char_t const*     inverseRefFieldName;
    } cli_field_descriptor;
</PRE>
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_drop_table"><pre>
int cli_drop_table(int                   session, 
	           char_t const*         tableName); 
</pre></A>
<DL><DD>
Drop table
<DL>
<DT><B>Parameters</B>
<DD><code>session</code> - session descriptor as returned by <A HREF="#cli_open"><code>cli_open</code></A>
<DD><code>tableName</code> - name of the created table
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>


<HR>

<A NAME = "cli_alter_index"><pre>
int cli_alter_index(int           session, 
	            char_t const* tableName 
		    char_t const* fieldName, 
		    int           newFlags); 
</pre></A>
<DL><DD>
Add or remove column index
<DL>
<DT><B>Parameters</B>
<DD><code>session</code> - session descriptor as returned by <A HREF="#cli_open"><code>cli_open</code></A>
<DD><code>tableName</code> - name of the created table
<DD><code>fieldName</code> - name of the field
<DD><code>newFlags</code> - new flags of the field, if index exists for this field, but is not specified in 
<code>newFlags</code> mask, then it will be removed; if index not exists, but is 
specified in <code>newFlags</code> mask, then it will be created.
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_freeze"><pre>
int cli_freeze(int statement);
</pre></A>
<DL><DD>
Freeze cursor. Make it possible to reused cursor after commit of the current transaction.
<DL>
<DT><B>Parameters</B>
<DD><code>statement</code> - statememt descriptor returned by <A HREF="#cli_statement"><code>cli_statement</code></A>
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_unfreeze"><pre>
int cli_unfreeze(int statement);
</pre></A>
<DL><DD>
Unfreeze cursor. Reuse previously frozen cursor.
<DL>
<DT><B>Parameters</B>
<DD><code>statement</code> - statememt descriptor returned by <A HREF="#cli_statement"><code>cli_statement</code></A>
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_seek"><pre>
int cli_seek(int statement, cli_oid_t oid);
</pre></A>
<DL><DD>
Position cursor to the record with specified OID
</pre></A>
<DT><B>Parameters</B>
<DD><code>statement</code> - statememt descriptor returned by <A HREF="#cli_statement"><code>cli_statement</code></A>
<DD><code>oid</code> - object identifier of the record to which cursor should be positioned
<DT><B>Returns</B>
<DD><code>&gt;= 0</code> - success, position of the record in the selection
<DD><code>&lt;  0</code> - error code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_skip"><pre>
int cli_skip(int statement, int n);
</pre></A>
<DL><DD>
Skip specified number of rows. 
</pre></A>
<DT><B>Parameters</B>
<DD><code>statement</code> - statememt descriptor returned by <A HREF="#cli_statement"><code>cli_statement</code></A>
<DD><code>n</code> -  number of objects to be skipped<BR><UL>
<LI>if <code>n</code> is positive, then this function has the same effect as executing cli_get_next() function <code>n</code> times.
<LI>if <code>n</code> is negative, then this function has the same effect as executing cli_get_prev() function <code>-n</code> times.
<LI>if <code>n</code> is zero, this method just reloads current record
</UL>
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>



<H2><A NAME = "localcli">Local implementation of CLI</A></H2>

Starting from version 2.65 GigaBASE provides local implementation of CLI interface. 
It means that now it is possible to access database directly from C application using CLI functions 
without starting separate server and socket communication overhead. 
Local implementation of CLI functions are included in main gigabase library.
So if you want to use remote CLI, link you application with <code>cli.lib</code> and if you want to
access database locally - link it with <code>gigabase.lib</code>.
To create local session you should use <code>cli_create</code> function instead of <code>cli_open</code>. 
Calling <code>cli_create</code> when your application is linked with <code>cli.lib</code> or 
<code>cli_open</code> when it is linked with <code>gigabase.lib</code> cause <code>cli_bad_address</code> 
error.<P>


<HR>

<A NAME = "cli_create"><pre>
int cli_create(char_t const* databasePath, 
               unsigned      transactionCommitDelay, 
	       int           openAttr, 
	       size_t        poolSize);
</pre></A>
<DL><DD>
Create connection to the local database
<DL>
<DT><B>Parameters</B>
<DD><code>databasePath</code> - path to the database file
<DD><code>transactionCommitDelay</code> - transaction commit delay (specify 0 to disable)
<DD><code>openAttr</code> - ask of cli_open_attributes. You can specify combination of the following 
attributes:<BR>
<UL>
<LI><code>cli_open_default</code>
<LI><code>cli_open_readonly</code>
<LI><code>cli_open_truncate</code>
<LI><code>cli_open_no_buffering</code>
</UL>
<DD><code>poolSize</code> - size of page pool (in pages), specify 0 to let GigaBASE automatically detect pool size
<DT><B>Returns</B>
<DD><code>&gt;= 0</code> - connection descriptor to be used in all other cli calls
<DD><code>&lt;  0</code> - error code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_attach"><pre>
int cli_attach(int session);
</pre></A>
<DL><DD>
Attach thread to the database. Each thread except one opened the database should first
attach to the database before any access to the database, and detach after end of the work with database
<DL>
<DT><B>Parameters</B>
<DD><code>session</code> - session descriptor as returned by <A HREF="#cli_open"><code>cli_open</code></A>
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_detach"><pre>
int cli_detach(int session, int detach_mode);
</pre></A>
<DL><DD>
Attach thread to the database. Each thread except one opened the database should first
attach to the database before any access to the database, and detach after end of the work with database
<DL>
<DT><B>Parameters</B>
<DD><code>session</code> - session descriptor as returned by <A HREF="#cli_open"><code>cli_open</code></A>
<DD><code>detach_mode</code> - bit mask representing detach mode
<PRE>
    enum cli_detach_mode {
        cli_commit_on_detach          = 1,
        cli_destroy_context_on_detach = 2
    };
</PRE>
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_prepare_query"><pre>
int cli_prepare_query(int session, char_t const* query);
</pre></A>
<DL><DD>
Prepare SubSQL query statement. 
<DL>
<DT><B>Parameters</B>
<DD><code>session</code> - session descriptor as returned by <A HREF="#cli_open"><code>cli_open</code></A>
<DD><code>query</code> - query string with optional parameters. Parameters are specified
as '%T' where T is one or two character code of parameter type using the same notation as in printf:
<TABLE>
<TR><TD>%d or %i</TD><TD>cli_int4_t</TD></TR>
<TR><TD>%f</TD><TD>cli_int8_t</TD></TR>
<TR><TD>%Li, %li, %ld or %Ld </TD><TD>cli_int8_t</TD></TR>
<TR><TD>%p</TD><TD>cli_oid_t</TD></TR>
<TR><TD>%s</TD><TD>char_t*</TD></TR>
</TABLE>
<DT><B>Returns</B>
<DD><code>&gt;= 0</code> - statement descriptor
<DD><code>&lt;  0</code> - error code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_execute_query"><pre>
int cli_execute_query(int statement, int for_update, void* record_struct, ...)
</pre></A>
<DL><DD>
Execute query previously prepared by <A HREF="#cli_prepare_query">cli_prepare_query</A>.<BR>
It is assumed that format of the destination C structure matches format of the target database table. 
For scalar and reference types mapping is obvious: you should use correspondent <code>cli_</code> types
in declaring structure and table fields. For array types, you should use <code>cli_array_t</code>
structure. Strings should be represented as <code>char*</code> and programmer should not try to 
deallocate them or copy this pointer and access it outside context of the current record. 

<DL>
<DT><B>Parameters</B>
<DD><code>statement</code> - statement descriptor returned by <A HREF="#cli_prepare_query">cli_prepare_query</A>
<DD><code>for_update</code> - not zero if fetched rows will be updated 
<DD><code>record_struct</code> - structure to receive selected record fields.
<DD><code>...</code> - varying list of query parameters
</TABLE>
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>

<A NAME = "cli_insert_struct"><pre>
int cli_insert_struct(int session, char_t const* table_name, void* record_struct, cli_oid_t* oid);
</pre></A>
<DL><DD>
Insert new record represented as C structure.<BR>
It is assumed that format of the destination C structure matches format of the target database table. 
For scalar and reference types mapping is obvious: you should use correspondent <code>cli_</code> types
in declaring structure and table fields. For array types, you should use <code>cli_array_t</code>
structure. Strings should be represented as <code>char_t*</code>.
<DL>
<DT><B>Parameters</B>
<DD><code>session</code> - session descriptor as returned by <A HREF="#cli_open"><code>cli_open</code></A>
<DD><code>table_name</code> - name of the destination table
<DD><code>record_struct</code> - structure specifying value of record fields
<DD><code>oid</code> - pointer to the location to receive OID of created record (may be NULL)
<DT><B>Returns</B>
<DD>result code as described in <A HREF="#cli_types"><code>cli_result_code</code></A> enum
</DL></DL>

<HR>


<H2><A NAME = "phpcli">Interface to PHP language</A></H2>

PHP is a server-side, cross-platform, HTML embedded scripting language.
Visit <A HREF="http://php.net">php.net</A> site for more information about this
language. GigaBASE interface to PHP is implemented in PHP itself and use 
sockets to connect to the GigaBASE server. It uses the same protocol as C CLI. 
Interface consists of two main classes:
<A HREF="gb_connection">gb_connection</A> and 
<A HREF="gb_statement">gb_statement</A>. Methods of these classes are very 
similar with functions of CLI C protocol.<P>

<H3><A NAME="cliphp_errors">Status codes</A></H3>

<TABLE><CAPTION><FONT SIZE=+1><B><U>CLI functions return codes</U></B></FONT></CAPTION>
<TR><TH>Error code</TH><TH>Description</TH></TR>
<TR><TD>cli_ok</TD><TD>Successful completion</TD></TR>
<TR><TD>cli_bad_address</TD><TD>Invalid format of server URL</TD></TR>
<TR><TD>cli_connection_refused</TD><TD>Connection with server could not be established</TD></TR>
<TR><TD>cli_bad_statement</TD><TD>Text of SQL statement is not correct</TD></TR>
<TR><TD>cli_parameter_not_found</TD><TD>Parameter was not found in statement</TD></TR>
<TR><TD>cli_unbound_parameter</TD><TD>Parameter was not specified</TD></TR>
<TR><TD>cli_column_not_found</TD><TD>No such column in the table</TD></TR>
<TR><TD>cli_incompatible_type</TD><TD>Conversion between application and database type is not possible</TD></TR>
<TR><TD>cli_network_error</TD><TD>Connection with server is broken</TD></TR>
<TR><TD>cli_runtime_error</TD><TD>Error during query execution</TD></TR>
<TR><TD>cli_close_statement</TD><TD>Access to the closed statement object</TD></TR>
<TR><TD>cli_unsupported_type</TD><TD>Unsupported type for parameter or column</TD></TR>
<TR><TD>cli_not_found</TD><TD>Record was not found</TD></TR>
<TR><TD>cli_not_update_mode</TD><TD>Attempt to update records selected by view only cursor</TD></TR>
<TR><TD>cli_table_not_found</TD><TD>There is no table with specified name in the database</TD></TR>
<TR><TD>cli_not_all_columns_specified</TD><TD>Insert statement doesn't specify values for all table columns</TD></TR>
<TR><TD>cli_not_fetched</TD><TD><A HREF="#cli_fetch"><code>cli_fetch</code></A> method was not called</TD></TR>
<TR><TD>cli_already_updated</TD><TD><A HREF="#cli_update"><code>cli_update</code></A> method was invoked more than once for the same record</TD></TR>
<TR><TD>cli_empty_parameter</TD><TD>Attempt to bind parameters which was not defined (assigned value or set type)</TD></TR>
<TR><TD>cli_closed_connection</TD><TD>Access to the closed connection object</TD></TR>
<TR><TD>cli_table_already_exists</TD><TD>Attempt to create table when table with such name already exists</TD></TR>
<TR><TD>cli_not_implemented</TD><TD>This function is not implemented by CLI API</TD></TR>
</TABLE>
<P>

<H3><A NAME="cliphp_types">Supported types</A></H3>

GigaBASE PHP interface supports the following PHP types for query parameters
and table columns:

<OL>
<LI>Integer
<LI>Real
<LI>String
<LI>Reference (represented by <A HREF="#gb_reference">gb_reference</A> object).
</OL>
<P>

<H3><A NAME="gb_connection_pool">Class gb_connection_pool</A></H3>

This class can be used for connection pooling. Some application (for example Web server scripts)
has to open database connections multiple times. To eliminate overhead of establishing connection
each time client request is proceeded, connection pool can be used. In this case connection is not 
actually closed, but instead of it just placed in the connection pool. Next time the connection with 
this server with the same user name and password is established, connection is just extracted from the 
pool.<P>

<HR>
<A NAME = "new_connection"><pre>
function new_connection($host_address, $host_port, $user_name = "guest", $password = "");
</pre></A>
<DL><DD>
Reuse existed pooled connection or make new one. 
<DL>
<DT><B>Parameters</B>
<DD><code>host_address</code> - string with server host name
<DD><code>host_port</code> - integer number with server port
<DD><code>user_name</code> - user name to login
<DD><code>password</code> - password to login
<DT><B>Returns</B>
<DD>gb_connection</DL></DL>

<HR>
<A NAME = "release_connection"><pre>
function release_connection($conxn);
</pre></A>
<DL><DD>
Place connection in the connection pool to make it available for future reuse.
This method implicitly commits the last transaction performed by the specified connection.
<DL>
<DT><B>Parameters</B>
<DD><code>conxn</code> - connection been placed in the pool.
</DL></DL>

<HR>

<A NAME = "close"><pre>
function close();
</pre></A>
<DL><DD>
Physically close all connections in the connection pool.
</DL>



<H3><A NAME="gb_connection">Class gb_connection</A></H3>

This class is responsible for establishing connection with the database 
and session specific operations. 

<HR>
<A NAME = "con_open"><pre>
function open($host_address, $host_port, $user_name = "guest", $password = "");
</pre></A>
<DL><DD>
Establish connection with the server
<DL>
<DT><B>Parameters</B>
<DD><code>host_address</code> - string with server host name
<DD><code>host_port</code> - integer number with server port
<DD><code>user_name</code> - user name to login
<DD><code>password</code> - password to login
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "con_close"><pre>
function close();
</pre></A>
<DL><DD>
Close connection.
<DL>
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>
<A NAME = "con_create_statement"><pre>
function create_statement($stmt);
</pre></A>
<DL><DD>
Create statement to be executed at server. Binding to the parameters and columns can be established.
<DL>
<DT><B>Parameters</B>
<DD><code>stmt</code> - string with SubSQL statement. Parameter names should
start with '%' character.
<DT><B>Returns</B>
<DD><code>gb_statement</code> object or <code>null</code> if 
specified statement is invalid</DL></DL>
</DL></DL>

<HR>

<A NAME = "con_insert"><pre>
function insert($obj, $oid);
</pre></A>
<DL><DD>
Insert object in the table with the same name as the object class.
<DL>
<DT><B>Parameters</B>
<DD><code>obj</code> - object to be stored in the database. Name of the 
object class should match with the name of some of database tables. 
<DD><code>oid</code> - reference to the variable to receive OID of created object.
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "con_commit"><pre>
function commit();
</pre></A>
<DL><DD>
Commit current database transaction
<DL>
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "con_rollback"><pre> 
function rollback();
</pre></A>
<DL><DD>
Rollback transaction
<DL>
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "con_show_tables"><pre>
function show_tables($tables) 
</pre></A>
<DL><DD>
Returns information about tables present in the database
<DL>
<DT><B>Parameters</B>
<DD><code>table</code> - reference of the variable to receive 
array with table names
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "con_describe"><pre>
function describe_table($name, $table) 
</pre></A>
<DL><DD>
Returns information about table column names and types
<DL>
<DT><B>Parameters</B>
<DD><code>name</code> - name of the table
<DD><code>table</code> - reference of the variable to receive associative
array <it>&lt;field-name,field-type&gt;</it>
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<H3><A NAME="gb_statement">Class gb_statement</A></H3>

This class represents prepared statement. Statement can be used several time 
with different parameters values. It should be explicitly deallocated
by <A HREF="stmt_free">free</A> method in order to release resources at 
server. As far as PHP provides no finalize mechanism, GigaBASE PHP API is
not able to do it automatically. Forgetting to free statements can cause
memory exhaustion at server.<P>


<A NAME = "stmt_bind_parameter">bind_parameter</A>
function bind_parameter($name, $binding);
</pre></A>
<DL><DD>
Bind parameter to the statement
<DL>
<DT><B>Parameters</B>
<DD><code>name</code> - string with name of parameter. Parameter name should
start with '%'.
<DD><code>binding</code> - reference to the parameter variable. 
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "stmt_bind_column"><pre>
function bind_column($name, $binding);
</pre></A>
<DL><DD>
Bind column of select or insert statement
<DL>
<DT><B>Parameters</B>
<DD><code>name</code> - string with name of the column.
<DD><code>binding</code> - reference to the column variable. 
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "stmt_bind_object"><pre>
function bind_object($name, $obj);
</pre></A>
<DL><DD>
Bind variable to receive fetched object or to specify inserted object
<DL>
<DT><B>Parameters</B>
<DD><code>binding</code> - reference to the object variable. 
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "stmt_bind_array"><pre>
function bind_array($name, $arr);
</pre></A>
<DL><DD>
Bind variable for fetching or inserting record as associative array of <i>&lt;field, value&gt;</i>
<DL>
<DT><B>Parameters</B>
<DD><code>binding</code> - reference to the array variable. 
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "stmt_fetch"><pre>
function fetch($for_update = false);
</pre></A>
<DL><DD>
Execute select statement.
<DL>
<DT><B>Parameters</B>
<DD><code>for_update</code> - <code>true</code> if fetched rows will be updated
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "stmt_fetch_objects"><pre>
function fetch_objects($arr);
</pre></A>
<DL><DD>
Return array with all fetched objects.
<DL>
<DT><B>Parameters</B>
<DD><code>arr</code> - reference to the variable to receive 
array with all selected objects
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "stmt_fetch_tuples"><pre>
function fetch_tuples($arr);
</pre></A>
<DL><DD>
Return array with all fetched tuples. Tuple is returned as associative array
of <i>&lt;field, value&gt;</i> pairs. 
<DL>
<DT><B>Parameters</B>
<DD><code>arr</code> - reference to the variable to receive 
array with all selected tuples
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "stmt_insert"><pre>
function insert($oid);
</pre></A>
<DL><DD>
Execute insert statement.
<DL>
<DT><B>Parameters</B>
<DD><code>oid</code> - reference to variable to receive OID of created object
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "stmt_get_first"><pre>
function get_first();
</pre></A>
<DL><DD>
Get first row of the selection.
<DL>
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "stmt_get_last"><pre>
function get_last();
</pre></A>
<DL><DD>
Get last row of the selection.
<DL>
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "stmt_get_next"><pre>
function get_next();
</pre></A>
<DL><DD>
Get next row of the selection. If get_next records is called
exactly after <A HREF="#stmt_fetch"><code>fetch</code></A> method call, 
is will fetch the first record in the selection. 
<DL>
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "stmt_get_prev"><pre>
function get_prev();
</pre></A>
<DL><DD>
Get previous row of the selection. If get_next records is called exactly 
after <A HREF="#stmt_fetch"><code>fetch</code></A> method call, is will fetch the last record  in selection.
<DL>
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "stmt_get_oid"><pre>
function get_oid();
</pre></A>
<DL><DD>
Get object identifier of the current record.
<DL>
<DT><B>Returns</B>
<DD><code>gb_reference</code> object with OID or null if no object was selected
</DL></DL>

<HR>

<A NAME = "stmt_update"><pre>
function update();
</pre></A>
<DL><DD>
Update the current row in the selection. You have to set
<code>for_update</code> parameter of <code>fetch</code> to 1 in order to be able
to perform updates. Updated value of row fields will be taken
from bound column variables.
<DL>
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "stmt_remove"><pre>
function remove();
</pre></A>
<DL><DD>
Remove all selected records. You have to set
<code>for_update</code> parameter of <code>fetch</code> to 1 in order to be able to remove records. 
<DL>
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<A NAME = "stmt_free"><pre>
function free();
</pre></A>
<DL><DD>
Deallocate statement and all associated data
<DL>
<DT><B>Returns</B>
<DD>status code</DL></DL>

<HR>

<H3><A NAME="gb_reference">Class gb_reference</A></H3>
Class <code>gb_reference</code> is used to represent database references. 
It contains the single fields - integer oid (object identifier). 
<P>


<H2> <A NAME = "advanced">Delayed transactions and online backup scheduler</A></H2>

GigaBASE supports ACID transactions. It means that after database is reported that transaction is committed,
it is guaranteed that database will be able to recover transaction in case of system fault
(except corruption of database image at hard disk). The only way to provide this feature on standard 
equipment (without non-volatile RAM for example) and under general-purpose operating systems 
(Windows, Unix, ...) is to perform synchronous write to the disk. "Synchronous" in this context means 
that operating system will not return control to the application until data will be really written to 
the disk. Unfortunately synchronous write is very time expensive operation - average disk access time 
is about 10ms, so it is hard to achieve performance more than 100 transactions per second.<P>

But in many cases it is acceptable to loose changes for few last seconds (but preserving consistency
of the database). With this assumption, database performance can be significantly increased.
GigaBASE provides "delayed transaction commit model" for such applications. When commit transaction delay
is non zero, database doesn't perform commit immediately, instead of it delay it for specified timeout.
After expiration of this timeout, transaction is normally committed, so it ensures that only changes
done within specified timeout can be lost in case of system crash.<P>

If thread, which has initiated delayed transaction, 
starts new transactions before delayed commit of transaction is performed, then
delayed commit operation is skipped. So GigaBASE is able to group several subsequent 
transactions performed by on client into the large single transaction. And it will greatly increase
performance, because it reduces number of synchronous writes and number created shadow pages (see section
<A HREF="#transaction">Transactions</A>).<P>

If some other client tries to start transaction before expiration of delayed commit timeout, then
GigaBASE force delayed commit to proceed and release resource for another thread. So concurrency is not
suffered from delayed commit.<P>

By default delayed commits are disabled (timeout is zero). You can sepcify commit delay 
parameter as second optional argument of <code>dbDatabase::open</code> method.
In <code>SubSQL</code> utility, it is possible to specify value of transaction commit
delay by setting <code>"GIGABASE_COMMIT_DELAY"</code> environment variable (seconds).<P>

Transaction commit scheme used in GigaBASE guaranty recovery after software and hardware fault if
image of the database at the disk was not corrupted (all information which was written to the disk
can be correctly read). If for some reasons, database file is corrupted, then the only way to
recover database is use backup (hoping that it was performed not so long time ago).<P>

Backup can be done by just copying database file when database is offline.
Class <code>dbDatabase</code> provides backup method which is able to perform online backup, 
which doesn't require stopping of the database. It can be called at any time by programmer.
But going further, GigaBASE provides backup scheduler, which is able to perform backup automatically.
The only things needed - name of the backup file and interval of time between backups.<P>

The method <code>dbDatabase::scheduleBackup(char_t const* fileName, time_t period)</code> 
spawns separate thread which performs backups to the specified location with specified period (in seconds).
If <code>fileName</code> ends with "?" character, then data of backup initiation is appended to the file 
name, producing the unique file name. In this case all backup files are kept on the disk (it is 
responsibility of administrator to remove too old backup files or transfer them to another media).
Otherwise backup is performed to the file with <code>fileName + ".new"</code> name, and after completion
of backup, old backup file is removed and new file is renamed to <code>fileName</code>.
Also in last case, GigaBASE will check the creation date of the old backup file (if exists) and adjust
wait timeout in such way, that delta of time between backups will be equal to specified period
(so if database server is started only for 8 hours per day and backup period is 24 hours, then
backup will be performed each day, unlike scheme with uniquely generated backup file names). 
<P>

It is possible to schedule backup processing in <code>SubSQL</code> utility by setting 
<code>GIGABASE_BACKUP_NAME</code> environment variable.
Period value is taken from <code>GIGABASE_BACKUP_PERIOD</code> environment variable if specified, otherwise it 
is set to one day. To recover from backup it is enough to copy some of the backup files instead of
corrupted database file.<P>
 


<H2><A NAME = "optimization">Query optimization</A></H2>

To reduce query execution time GigaBASE uses indices, inverse references and
query parallelization. The following
sections supplies more information about these optimizations.<P>

<H3><A NAME = "indices">Using indices in queries</A></H3>
Indices is traditional approach for increasing RDBMS performance. GigaBASE
uses <A HREF="#btree">B-tree</A> for implementing index access to the data.

GigaBASE uses simple rules for applying indices,
allowing programmer to predict when index will be used. Check for
index applicability is done during each query execution, so decision
can be made depending on values of operands.
The following rules describes algorithm of applying indices by GigaBASE:<P>

<UL>
<LI>Compiled condition expression is always inspected from left to right.
<LI>If topmost expression is <B>AND</B> then try to apply index to
left part of expression, using right part as filter.
<LI>While topmost expression is <B>OR</B> and index can be applied
to left part of the expression, then apply index and test right part
for possibility to use indices.
<LI>Otherwise, index is applicable to the expression, when
<OL>
   <LI> the topmost expression is relational operation
       (<code>= &lt; &gt; &lt;= &gt;= between like</code>)
   <LI> type of operands is boolean, numeric, string or reference
   <LI> right operand(s) of the expression is either constant literal
        or C++ variable
   <LI> left part is indexed field of the record
   <LI> relational operation is one <code>= &gt; &gt;= &lt; &lt;= between</code>
   or operation is <code>like</code> and pattern string contains no wildcard
   symbol <code>%</code> or <code>_</code> in first position.
</OL>
</UL><P>

If index is used to search prefix of <code>like</code> expression, and
suffix is not just '%' character, then index search operation can return
more records than really match the pattern. In this case we should filter
index search output by applying pattern match operation.<P>

When search condition is disjunction of several subexpressions
(expression contains several alternatives combined by <code>or</code>
operator), then several indices can be used for query execution.
To avoid record duplicates in this case, bitmap is used in cursor
to mark records already included in the selection.<P>

If search condition requires sequential table scan, B-tree index
still can be used if <code>order by</code> clause contains the single
record field for which B-tree index is defined. As far as sorting is very
expensive operation, using of index instead of sorting significantly
reduce time of query execution.<P>

It is possible to check which indices are used for query execution
and number of probes done during index search be compiling GigaBASE
with option <code>-DDEBUG=DEBUG_TRACE</code>. In this case GigaBASE will
dump trace information about database functionality including information
about indices.<P>


<H3><A NAME = "inverse">Inverse references</A></H3>
Inverse references provides efficient and reliable way of establishing
relations between tables. GigaBASE uses information about inverse reference
when record is inserted/updated/deleted and also for query optimization.
Relations between records can be of one of the following types:
<I>one-to-one, one-to-many</I> and <I>many-to-many</I>.

<UL>
<LI><I>One-to-one</I> relation is represented by reference field in self and
target records.
<LI><I>One-to-many</I> relation is represented by array of references field in
self record and reference field in the record of referenced table.
<LI><I>Many-to-one</I> relation is represented by reference field in self
record and array of references field in the record of target table.
<LI><I>Many-to-many</I> relation is represented by array of references fields in
self and target records.
</OL><P>

When record with declared relations is inserted in the table, inverse
references in all tables been in relation with this records are updated to
point to this record. When record is updated and field specifying
records relationships are changed, then inverse references are also
reconstructed automatically, by removing references to updated record
from that records which are no more in relation with this record and
setting inverse references to updated record for new records included in
relation. And when record is deleted from the table, references to it are
removed from all inverse reference fields.<P>

Due to efficiency reasons, GigaBASE is not able to guaranty consistency of
all references. If you remove record from the table, there are still
can be references to removed record in database. Accessing these references
can cause unpredictable behavior of application and even database corruption.
Using inverse references allows to eliminate this problem, because
all references will be updated automatically and consistency of references
is preserved.<P>


Lets use the following table definitions as example:<P>

<PRE>
class Contract;

class Detail {
  public:
    char const* name;
    char const* material;
    char const* color;
    real4       weight;

    dbArray&lt; dbReference&lt;Contract&gt; &gt; contracts;

    TYPE_DESCRIPTOR((KEY(name, INDEXED),
		     KEY(material, INDEXED),
		     KEY(color, INDEXED),
		     KEY(weight, INDEXED),
		     RELATION(contracts, detail)));
};

class Supplier {
  public:
    char const* company;
    char const* location;
    bool        foreign;

    dbArray&lt; dbReference&lt;Contract&gt; &gt; contracts;

    TYPE_DESCRIPTOR((KEY(company, INDEXED),
		     KEY(location, INDEXED),
		     FIELD(foreign),
		     RELATION(contracts, supplier)));
};


class Contract {
  public:
    dbDateTime            delivery;
    int4                  quantity;
    int8                  price;
    dbReference&lt;Detail&gt;   detail;
    dbReference&lt;Supplier&gt; supplier;

    TYPE_DESCRIPTOR((KEY(delivery, INDEXED),
		     KEY(quantity, INDEXED),
		     KEY(price, INDEXED),
		     RELATION(detail, contracts),
		     RELATION(supplier, contracts)));
};
</PRE><P>

In this example there are one-to-many relations between tables
Detail-Contract and Supplier-Contract. When <code>Contract</code>
record is inserted in database, it is necessary only to set references
<code>detail</code> and <code>supplier</code> to correspondent
records of <code>Detail</code> and <code>Supplier</code> tables.
Inverse references <code>contracts</code> in these records will be updated
automatically. The same is happened when <code>Contract</code> record is
removed, references to removed record will be automatically excluded
from <code>contracts</code> field of referenced <code>Detail</code> and
<code>Supplier</code> records.<P>

Moreover using inverse reference allows to chose more effective plan of query
execution. Consider the following query selecting all details
shipped by some company:<P>

<PRE>
    q = "exists i:(contracts[i].supplier.company=",company,")";
</PRE>

The straightforward approach to execution of this query is scanning
<code>Detail</code> table and testing each record for this condition.
But using inverse reference we can choose another approach: perform
index search in <code>Supplier</code> table for records with specified
company name and then use inverse references to locate records from
<code>Detail</code> table been in transitive relation with
selected supplier records. Certainly we should eliminate duplicates of
records, which can appear because company can ship a number of different
details. This is done by bitmap in cursor object.
As far as index search is significantly faster than sequential search
and accessing record by reference is very fast operation, total
time of such query execution is much shorter comparing with
straightforward approach.<P>

Starting from 1.21 version GigaBASE supports cascade deletes.
If field is declared using OWNER macro, the record is treated as owner of
the hierarchical relation. When the owner records is removed all
members of this relation (records referenced from the owner) will be
automatically removed. If member record of the relation should contain
reference to the owner record, this field should be declared using
RELATION macro.<P>



<H3><A NAME = "par">Parallel query execution</A></H3>

GigaBASE is able to split query into several parallel jobs, which will be
executed without any contention with each other. Parallelization of query
is done by GigaBASE only for sequential scans if the table. In this case
splitting job between <I>N</I> processors can reduce query execution
time about <I>N</I> times (even more if result should be sorted).<P>

To split table scan, GigaBASE starts <I>N</I> threads each of them
tests <I>N</I>-s record of the table (i.e. thread number 0 test records
<I>0,N,2*N</I>,... thread number 1 test records <I>1,1+N,1+2*N</I>,... and so on). Each thread builds its own list
of selected records. After termination of all threads, these lists
are concatenated to construct the single result list.<P>

If result should be sorted, then each thread, after finishing the table scan,
sorts the records it selected. After termination of all threads,
their lists are merged (as it is done with external sort).<P>

Parallel query execution is controlled by two parameters: number of spawned
threads and parallel search threshold. First is specified in
<code>dbDatabase</code> class constructor or set by
<code>dbDatabase::setConcurrency</code> method. Zero value of this parameter
asks GigaBASE to automatically detect number of online CPUs in the system and
spawn exactly this number of threads. By default number of threads is set to 1,
so no parallel query execution takes place.<P>

Parallel search threshold parameter specifies minimal number of records in the
table for which parallelization of query can improve query performance
(starting of threads has its own overhead). This parameter is static
component of <code>dbDatabase</code> class and can be changed by application at
any moment of time.<P>

Parallel query execution is not possible when:<P>

<OL>
<LI>Indices are used for query execution.
<LI>Number of records in the table is less than <code>dbDatabase::dbParallelScanThreshold</code>;
<LI>Selection limit is set for the cursor;
<LI>The query includes <code>start from</code> part;
</OL><P>


<H2> <A NAME = "replication">GigaBASE replication mechanism</A></H2>

Starting from version 2.59 GigaBASE provides master-slaves replication mechanism.
All updates are performed only by master and replicated to arbitrary number
of slaves. Slaves can execute only read-only queries. In case of fault, 
one of the slaves can become master.<P>

Replication is implemented in <code>dbReplicatedDatabase</code> class
which is derived from <code>dbDatabase</code> class. In addition to
parameters passed to <code>dbDatabase</code> constructor, the constructor
of <code>dbReplicatedDatabase</code> class allows to specify 
<i>replication manager class</i>. Also it always opens the database in full-access
mode, so this parameter is skipped.<P>

Replication at master and slaves nodes is start by <code>open</code> method.
It accepts to additional parameters: master host address 
(included port separated from name by ':') and number of replicas.
If number of replicas is zeros, then this database is assumed to be slave
and tries to establish connection with master.
Otherwise node is assumed to be master and it tries to accept specified number
of connections with slaves. Control is not returned from open method
until all connections are established.<P>

Replication at master is implicitly stopped by <code>close</code> method
or can be explicitly terminated by <code>stopMasterReplication()</code>
method. Replication at slave is terminated when it receives termination
request from master or when connection with master is broken.
If slave receives termination request from master, it means that currently 
it has completely the same database as master and can continue work 
with the database (even update it). But if slave detects disconnection with
client, then its database is inconsistent and recovery should be performed
(slave should exit without closing and the try to open database once again).<P>

GigaBASE replication mechanism works in the assumption that at startup
content of database files of master and slaves is identical. GigaBASE doesn't provide
mechanism for synchronizing state of repositories if some node was unavailable for 
some time and then tries to become new slave or master. In this case database
file should be replicated at the node using standard network file copy mechanism
(certainly all databases should be offline at this moment).<P>

Slave can inspect and control replication process by implementing
<code>dbReplicationManager</code> abstract class and passing it to 
<code>dbReplicatedDatabase</code> constructor. This class defines the following
abstract method:<P>

<TABLE BORDER><TR><TH>Method</TH><TH>Description</TH></TR>
<TR><TD><code>bool connectionBroken(char* hostName)</code></TD><TD>This method is invoked when 
connection with master/slave is broken</TD></TR>
<TR><TD><code>void transactionCommitted()</code></TD><TD>This method is invoked when 
transaction is completely transferred to the client. This method can be used for example 
to perform refresh in GUI component</TD></TR>
<TR><TD><code>void replicationEnd()</code></TD><TD>This method is called when slave receives 
replication end request from master</TD></TR>
<TR><TD><code>bool preserveSlaveConsistency()</code></TD><TD>This method is used to specify
transaction policy at slave. If this method returns true, then GigaBASE will preserve 
consistency of slave replica of the database. So in case of master or slave crash, 
it will be possible to recover and continue work with slave database. 
If this method returns false, the slave performance is greatly increased (because of avoiding 
flushing file buffers to the disk), but in case of fault, slave database may be stayed in 
inconsistent state
</TD></TR>
</TABLE><P>

Example of replication can be found in <code>testreplic.cpp</code> example.
At master you should launch it with the following command line:

<PRE>
      testreplic master<B>N</B> [<i>master-host-address</i>] [<i>number-of-iterations</i>]

where <B>N</B> - is positive integer specifying number of replicas
</PRE>

At slave(s) node it can be run with the following command:

<PRE>
      testreplic slave [<i>master-host-address</i>]
</PRE>
 


<H2> <A NAME = "gist">Generalized search tree</A></H2>

In addition to built-in B-Tree and R-Tree indices, GigaBASE makes it possible
for programmer to define their own indices. GigaBASE provides interface to GiST - Generalized
Search Tree. It is not integrated in GigBASE query mechanism, but rather provides
yet another way to select GigaBASE objects. GigaBASE uses GiST C++ library from University of 
California. GigaBASE provides implementation of <code>GiSTstore</code> interface which is 
responsible for storing/retrieving GiST pages in database. GigaBASE includes
release 0.9 beta 1 of the GiST C++ library with additional <code>GiSTdb.cpp</code> and 
<code>GiSTdb.h</code> files and changed BTree, RTree and RSTree examples, patched to work
with GigaBASE instead of plain fails.<P>
<A HREF="GiST/doc/index.html">GiST documentation is available here</A>


<H2> <A NAME = "implementation">GigaBASE implementation issues</A></H2>

This section describes some aspects of GigaBASE implementation.
It is not necessary to read this section unless you want to know
about GigaBASE internals.<P>

<H3> <A NAME = "memory">Memory allocation</A></H3>

Memory allocation is performed in GigaBASE by bitmap. Memory is allocated in
chunks called allocation quantum. In current version of GigaBASE size of
allocation quantum is 64 byte. It means that size of all allocated objects is
aligned on 64 byte boundary. Each 64 byte of database memory is represented by
one bit in the bitmap. To locate hole of requested size in bitmap, GigaBASE
sequentially searches bitmap pages for correspondent number of successive
cleared bits. GigaBASE use three arrays indexed by bitmap byte, which
makes possible fast calculation of hole offset and size within the byte.<P>

GigaBASE performs cyclic scanning of bitmap pages. It keeps identifier
of current bitmap page and current position within the page. Each time
when allocation request arrives, scanning of the bitmap starts from the
current position.
When last allocated bitmap page is scanned, scanning continues from the
beginning (from the first bitmap page) and until current position.
When no free space is found after full cycle through all bitmap pages,
new bulk of memory is allocated. Size of extension is maximum of
size of allocated object and extension quantum. Extension quantum is parameter
of database, specified in constructor. Bitmap is extended to be able to map
additional space. If virtual space is exhausted and no more
bitmap pages can be allocated, then <code>OutOfMemory</code> error
is reported.<P>

Allocation memory using bitmap provides high locality of references
(objects are mostly allocated sequentially) and also minimizes
number of modified pages. Minimization of number of modified pages is
significant when commit operation is performed and all dirty pages should
be flushed on the disk. When all cloned objects are placed sequentially,
number of modified pages is minimal and so transaction commit time is also
reduced. Using extension quantum also helps to
preserve sequential allocation. Once bitmap is extended, objects will
be allocated sequentially until extension quantum will be completely used.
Only after reaching the end of the bitmap, scanning restarts from the beginning
searching for holes in previously allocated memory.<P>


To reduce number of bitmap pages scans, GigaBASE associates descriptor with
each page, which is used to remember maximal size of the hole on the page.
Calculation of maximal hole size is performed in the following way:
if object of size <I>M</I> can not be allocated from this bitmap pages,
then maximal hole size is less than <I>M</I>, so <I>M</I>
is stored in the page descriptor if previous value of descriptor is large
than <I>M</I>. For next allocation of object of size greater or
equal than <I>M</I>, we will skip this bitmap page. Page descriptor
is reset when some object is deallocated within this bitmap page.<P>

Some database objects
(like hash table pages) should be aligned on page boundary
to provide more efficient access. GigaBASE memory  allocator checks requested
size and if it is aligned on page boundary, then address of
allocated memory segment is also aligned on page boundary. Search of free hole
will be done faster in this case, because GigaBASE increases step of current
position increment according to the value of alignment.<P>

To be able to deallocate memory used by object, GigaBASE needs to keep
somewhere
information about object size. GigaBASE memory allocator deals with two types
of objects - normal table records and page objects.
All table records are prepended by record header, which contains
record size and pointer of L2-list linking all records in the table.
So size of the table record object can be extracted from record header.
Page objects always occupies the whole database page are are allocated at
the positions aligned on page boundary. Page objects has no headers.
GigaBASE distinguish page objects
with normal object by using special marker in object index.<P>

By default maximal database size supported by GigaBASE is limited to 4Gb.
It is possible to increase (or reduce) this value by specifying
values of <code>dbDatabaseOffsetBits</code> parameter. Default value of this
parameter is 32. When value of this parameter is not greater than 32,
GigaBASE will use 4 byte integers to represent offsets with database
This two times reduce size of object index and also number of bitmap page
handles reserved in index. By default GigaBASE is not able to handle more than
1Gb objects. It is possible to overcome this limitation by specifying value of
<code>dbDatabaseOidBits</code> parameter greater than 32.<P>


<H3> <A NAME = "transaction">Transactions</A></H3>

Each record (object) in GigaBASE has unique identifier (OID).
Object identifiers
are used to implement references between objects. To locate object by
reference, its OID is used as index in array of object offsets within the file.
This array is called <I>object index</I> and element of this array -
<I>object handle</I>. These are two copies of object
indices in GigaBASE, one of which is current and other - shadow.
Header of database contains pointers to both object indices and indicator
which index is current at this moment.<P>

When object is modified first time, it is cloned
(copy of the object is created) and object handle in current index is
changed to point to newly created object copy. And shadow index still
contains handle which points to the original version of the object.
All changes are done with the object copy, leaving original object unchanged.
GigaBASE marks in special bitmap page of the object index, which contains
modified object handle.<P>

When transaction is committed, GigaBASE first checks if size of object index
was increased during current transaction. If so, it also reallocates shadow
copy of object index. Then GigaBASE frees memory for all "old objects",
i.e. objects which was cloned within transaction. Memory can not be
deallocated before commit, because we wants to preserve consistent
state of the database by keeping cloned object unchanged.
If we deallocate memory immediately after cloning, new object can be
allocated at the place of cloned object and we loose
consistency. As far as memory deallocation is done in GigaBASE by bitmap
using the same transaction mechanism as for normal database objects,
deallocation of object space will require clearing some bits in bitmap page,
which also should be cloned before modification. Cloning bitmap page will
require new space for allocation the page copy, and we can reuse space of
deallocated objects. And it is not acceptable due to the reason explained
above - we will loose database consistency. That is why deallocation
of object is done in two steps. When object is cloned, all bitmap pages
used for marking objects space, are also cloned (if not
not cloned before). So when transaction is committed, we only clear bits in
bitmap pages and no more requests for allocation memory can be generated at
this moment.<P>

After deallocation of old copies, GigaBASE flushes all modified pages on disk
to synchronize content of the memory and disk file. After that GigaBASE
changes current object index indicator in database
header to switch roles of the object indices. Now object index, which was
current becomes shadow, and shadow index becomes current. Then GigaBASE again
flushes modified page (i.e. page with database header) on disk, transferring
database to new consistent state.
After that GigaBASE copies all modified handles from new object index
to object index which was previously shadow and now becomes current.
At this moment contents of both indices is synchronized and GigaBASE is ready
to start new transaction.<P>

Bitmap of modified object index pages is used to minimize time of committing
transaction. Not the whole object index, but only its modified pages should be
copied. After committing of transaction bitmap is cleared.<P>

When transaction is explicitly aborted by <code>dbDatabase::rollback</code>
method, shadow object index is copied back to the current index, eliminating
all changes done by aborted transaction. After the end of copying,
both indices are identical again and database state corresponds to the moment
before the start of current transaction.<P>

Allocation of object handles is done by free handles list. Header of the list
is also shadowed and two instances of list headers are stored in database
header. Switch between them is done in the same way as switch of
object indices. When there are no more free elements in the list, GigaBASE
allocates handles from the unused part of new index. When there is no
more space in the index, it is reallocated. Object index is the only
entity in database whose is not cloned on modification. Instead of this
two copies of object index are always used.<P>

There are some predefined OID values in GigaBASE. OID <I>0</I> is reserved
as invalid object identifier. OID <I>1</I> is used as identifier of
metatable object -
table containing descriptors of all other tables in database. This table
is automatically constructed while database initialization and descriptors of
all registered application classes are stored in this metatable.
OID starting from <I>2</I> are reserved for bitmap pages.
Number of bitmap pages depends on database maximum virtual space.
For one terabyte virtual space, 8 Kb page size and 64 byte allocation quantum,
32K bitmap pages are required. So 32K handles are reserved in object index for
bitmap. Bitmap pages are allocated on demand, when database size is extended.
So OID of first users object will be 0x8002.<P>


<H3> <A NAME = "recovery">Recovery</A></H3>

Recovery procedure is trivial in GigaBASE. There are two instances of
object index, one of which is current and another corresponds to
consistent database state. When database is opened, GigaBASE checks database
header to detect if database was normally closed. If not
(<code>dirty</code> flag is set in database header), then GigaBASE performs
database recovery. Recovery is very similar to rollback of transaction.
Indicator of current index in database object header is used to
determine index corresponding to consistent database state and object handles
from this index are copied to another object index, eliminating
all changes done by uncommitted transaction. As far as the only action
performed by recovery procedure is copying of objects index (really only
handles having different values in current and shadow indices are copied to
reduce number of modified pages) and size of object index is small,
recovery can be done very fast.
Fast recovery procedure reduces "out-of-service" time of application.<P>

There is one hack which used in GigaBASE to increase database performance.
All records in the table are linked in L2-list, allowing efficient traversal
through the list and insertion/removing of records.
Header of the list is stored in table object (which is record of
<code>Metatable</code> table). L2-list pointers are
stored at the beginning of the object together with object size.
New records are always appended in GigaBASE to the end of the list.
To provide consistent inclusion in database list we should clone last record
in the table and table object itself. But record size can be big enough, so
cloning of last record for each inserted record can cause significant space
and time overhead.<P>

To eliminate this overhead GigaBASE do not clone last record allowing
temporary inconsistency of the list. In which state will be list if
system fault happens before commit of the transaction ? Consistent
version of table object will point to the record which was last record in
previous consistent state of database. But as far as this record was not
cloned, it can contain pointer to next record, which doesn't exist in this
consistent database state. To fix this inconsistency, GigaBASE checks all tables
in database during recovery procedure and if last record in the
table contains not null next reference, it is changed to null to restore
consistency.<P>

If database file was corrupted on disk, the only way of database recovery
is to use backup file (certainly if you do not forget to make it).
Backup file can be made by interactive SQL utility using <code>backup</code>
command or from application by <code>dbDatabase::backup()</code> method.
It creates snapshot of database in specified file (it can be name of a
device, tape for example). As far as database file is always in consistent
state, the only think needed to perform recovery from the backup file
is to replace original database file with backup file. If backup was stored
at tape or some other external device, it should be first extract to the
disk.<P>

If some of application starts transaction, locks database and then crashes,
then database is left in locked state and no other application can access it.
To restore from this situation you should stop all applications working with
database. First application opening the database after this will initialize
database monitor and perform recovery after crash.<P>


<H3> <A NAME = "btree">B-tree</A></H3>

B-Tree is the classical structure for implementing database indices.
B-tree minimizes number of disk access needed to locate data by key.
As far as disk access are the most expensive operations, minimizing
of disk reads will reduce query execution time.
The main idea of B-Tree is to produced balanced tree with large width and small
depth. All leaf pages in B-tree have the same depth
(distance from the root) page. This distance is called tree height.
Number of pages accessed during index search is equal to the tree
height, so reducing tree height will minimize number of disk operations.
<P>

The pages of B-tree contain key values and references to the objects.
For scalar values, key values and object references are stored in two arrays
grown towards each other. Array of key values grows from the beginning of
the page to the page end. Object reference corresponding to the key value
in <code>i</code>-th position is stored in the position
<code>*((oid_t*)(page + page_size) - i - 1)</code>. For string keys,
leaf page contains array of elements with object reference, string size and
string body offset within page. Strings bodies are allocated starting from the
end of the page.<P>

To keep minimal tree height, B-tree makes a restriction for minimal
number of nodes at the page. All internal pages except root, should have
not less than half of the pages used (this criteria can be changed).
As far as length of string keys stored in leave pages are different,
it is not possible to set limitation on the number of nodes for pages with string
keys. Instead of this limitation for size used at leaf page is specified.
If more than half of the page is free, then reconstruction of the tree is
needed.<P>

All operations with B-tree (insert/find/remove) have <I>log(N)</I> complexity,
where <I>N</I> is number if nodes in the tree (size of the table).
Elements are stored at B-Tree pages in increasing order, so it is possible to
use binary search to locate element at the page.<P>

When new item is inserted in the tree, adding new element to the page can
cause page overflow. In this case, new page is created and half of the
nodes from overflown page are moved to the newly created page.
As far as creating of new page cause insertion of new element in the parent
page, propagation of inserts can continue to the root of the tree.
If root page is splitted, then new root page is created and tree height is
increased.<P>

When item is removed from the page, page underflow can happen - more than half
of the page is not used. In this case neighbor page is investigated and
either merge of neighbor page with underflown page takes place,
either reallocation of nodes between underflown page and neighbor page,
restoring tree invariants, is performed. As well as with insert operations,
propagation of removes can reach the root page and when the single element
is left at the root page, this root page is deallocated and tree height
is decreased.<P>

At the end of B-tree description we want to illustrate efficiency of
B-tree search operations. Lets say we have 150 million records in the
table with string primary key having average length 8 bytes. Then
average number of elements at leave pages is
<code>page_size / (string_key_element + average_string_length) * 3 / 4 = 8192
/ 16 * 3 / 4 = 384</code>.
So there are about <code>150000000 / 384 = 390625</code> leave pages.
Average number of items at the internal page is
<code>page_size / 8 * 3 / 4 = 768</code>
and <code>512</code> for the root page. Because
<code>512*768 = 393216 > 390625</code>, then height of the B-tree will be 3.
As far as root has very goods chances to be always present in page pool,
index search of record within 150 millions object will require only two
page reads.<P>


<H2> <A NAME = "subsql">Interactive SQL</A></H2>

Interactive SUBSQL utility allows to browse any GigaBASE database and to perform
some administration functions with it. Also import/export of data
from database can be done by SUBSQL utility. Name SUBSQL was chosen
to express that only subset of SQL is implemented by this utility.<P>

The following rules in BNF-like notation specifies grammar of
SUBSQL directives:<P>

<PRE>
<I>directive</I> ::=
    <B>select</B> (<B>*</B>) <B>from</B> <I>table-name</I> <I>select-condition</I> <B>;</B>
  | <B>insert into</B> <I>table-name</I> <B>values</B> <I>values-list</I> <B>;</B>
  | <B>create index on</B> <I>table-name.field-name</I> <B>;</B>
  | <B>create table</B> <I>table-name</I> <B>(</B><I>field-descriptor</I> {<B>,</B> <I>field-descriptor</I>}<B>)</B> <B>;</B>
  | <B>alter table</B> <I>table-name</I> <B>(</B><I>field-descriptor</I> {<B>,</B> <I>field-descriptor</I>}<B>)</B> <B>;</B>
  | <B>update</B> <I>table-name</I> <B>set</B> <I>field-name</I> <B>=</B> <I>expression</I> {<B>,</B> <I>field-name</I> <B>=</B> <I>expression</I>} <B>where</B> <I>condition</I> <B>;</B>
  | <B>drop index</B> <I>table-name.field-name</I> <B>;</B>
  | <B>drop table</B> <I>table-name</I>
  | <B>open</B> (<B>@</B>)<I>database-file-name</I> <B>;</B>
  | <B>delete from</B> <I>table-name</I>
  | <B>backup</B> <I>backup-file-name</I>
  | <B>start server</B> <I>server-URL</I> <I>number-of-threads</I>
  | <B>stop server</B> <I>server-URL</I>
  | <B>start http server</B> <I>server-URL</I> 
  | <B>stop http server</B> <I>server-URL</I>
  | <B>restore</B> <I>backup-file-name</I> <I>database-file-name</I>
  | <B>export</B> <I>xml-file-name</I>
  | <B>import</B> <I>xml-file-name</I>
  | <B>commit</B>
  | <B>rollback</B>
  | <B>autocommit</B> (<B>on</B> | <B>off</B>)
  | <B>show</B>
  | <B>exit</B>
  | <B>help</B>

<I>table-name</I> ::= <I>identifier</I>
<I>values-list</I> ::= <I>tuple</I> { <B>,</B><I> tuple</I> }
<I>tuple</I> ::= <B>(</B> <I>value</I> { <B>,</B> value } <B>)</B>
<I>value</I> ::= <I>number</I> | <I>string</I> | <B>true</B> | <B>false</B>
               | <I>tuple</I>
<I>index</I> ::= <B>index</B> | <B>hash</B>
<I>field-descriptor</I> ::= <I>field-name</I> <I>field-type</I> (<B>inverse</B> <I>field-name</I>)
<I>field-name</I> ::= <I>identifier</I> { <B>.</B> <I>identifier</I> }
<I>database-file-name</I> ::= <B>'</B>file-name<B>'</B>
               | <B>'@</B>file-name<B>'</B> |
<I>backup-file-name</I> ::=  <B>'</B>file-name<B>'</B>
<I>xml-file-name</I> ::= <B>'</B>file-name<B>'</B>
<I>server-URL</I> ::= <code>'HOST:PORT'</code>
</PRE><P>

SUBSQL automatically commits read-only transaction after each
select statement in order to release shared database lock as soon as possible.
But all database modification operations should be explicitly committed
by <code>commit</code> statement or undone by <code>rollback</code>
statement. Directives <code>open</code> and <code>exit</code> first closes
opened database (if it was opened) and so implicitly commits last transaction.
If database file name is prepended by <code>@</code> symbol, then
file with such name (without <code>@</code>) is treated as descriptor
of multifile, containing specification of multifile segments.<P>

Select statement always print all record fields. GigaBASE doesn't support
tuples, and result of the selection is always set of objects (records).
Format of select statement output is similar with one accepted by insert
statement (with exception of reference fields). So it is possible to
export/import database table without references by means of
<code>select/insert</code> directives of SUBSQL.<P>

Select statement prints references in format
<code>"#hexadecimal-number"</code>. But it is not possible to use this format
in <code>insert</code> statement. As far as object references are represented
in GigaBASE by internal object identifiers, reference field can not be set in
<code>insert</code> statement (when objects are inserted in database they will
be assigned new OID, so there is not sense in specifying reference field
in <code>insert</code> statement). To ensure database reference consistency,
GigaBASE just ignores reference fields when new records are inserted in the table
with references. You should specify value 0 at the place of reference fields.
If you omit '*' symbol in select statement, GigaBASE will output object
identifiers of each selected record.<P>

It is necessary to provide values for all records fields in <code>insert</code>
statement, no default values are not supported. Components of structures and
arrays should be enclosed in parentheses.<P>

It is not possible to create or drop indices and tables while other
applications are working with database. Such operations change
database scheme and after such modification other applications state
will become incorrect. But <code>delete</code> operation
doesn't change database scheme, so it can be performed as normal transaction,
when database is concurrently used by several applications.
If SubSQL hangs trying to execute some statement, then some other application
holds the lock on database, preventing SUBSQL from accessing it.<P>


SubSQL can be used to start CLI and HTTP servers.
CLI server accept connections of clients using CLI protocol to access database.
Each client is server by separate thread. SubSQL maintains pool of thread, taking 
thread from the pool when client is attached and place thread back in the pool when 
client is disconnected.<P>

HTTP server is used to provide view-only access to the database from Web browsers.
Unlike CLI servers, only one instance of HTTP server can be started. 
To view main database page, just type in your Web browser URL which you have
specified in <code>start http server</code> command.<P>

Database can be exported as XML file using SubSQL <code>export</code> command.
This command cause dump of the whole database in XML format to the specified file according
to the following rules:
<UL>
<LI>Each record is represented by XML element with the same name as the table.
<LI>Each record contains <code>id</code> attribute which specified OID of the object.
<LI>Each record field is represented by the XML element with the same name as field.
<LI>Values of scalar types are printed as decimal integer or float numbers.
<LI>String literals are enclosed in <code>""</code>. All characters greater than 'z' or less then ' ' or
equal to '%' or '"' are printed as two hex digits prepended by '%': space character = "%20".
<LI>Raw binary types are represented by string where each byte is represented by '%' and two hex digits.
<LI>Reference types are represented by <code>&lt;ref id=OID/&gt;</code> element, where OID is object identifier of
referenced object.
<LI>Array is represented as sequence of <code>&lt;array-element&gt;</code> elements
<LI>Rectangle is represented by <code>&lt;rectangle&gt;</code> element with two <code>&lt;vertex&gt;</code>
subelements containing list of coordinate attributes.
</UL><P>

Produced XML file can be used to export data to other programs or for flexible restoring of database.
To be able to import data from XML file you should have all table created. In C++ application it is enough
to open and close database, then all described tables will be created. SubSQL <code>import</code>
command will import data from XML file, mapping OIDs of records specified in XML file to OIDs of created records. 
Such export/import sequence can be used to convert database to the new format. For example, if you
increase value of <code>dbDatabaseOffsetBits</code> constant to extend database file size limit, format of database will be incompatible with one created with previous value of <code>dbDatabaseOffsetBits</code>. In this
case export/import can be used to prevent loosing of all data stored in the database.<P>
`
ets say that you have database <i>"YourOldDatabase.dbs"</i> created by your application <i>YourOldApplication</i>
and you want to convert it to new format so it can be used by new version of your application: 
<i>YourNewApplication</i>. First Of all you need to initialize new database. To do it you should run
<i>YourNewApplication</i> and open/close database <i>"YourNewDatabase.dbs"</i> in it.
Then prepare two SubSQL command files:<P>

<DL>
<DT><code>export.sql</code>:
<DD><pre>
open 'YourOldDatabase.dbs';
export '-'
exit
</pre>
<DT><code>import.sql</code>:
<DD><pre>
open 'YourNewDatabase.dbs';
import '-'
exit
</pre>
</DL>

Convesion can be done using the following command:

<pre>
subsql export.xml | subsql import.xml
</pre>
<P>

To be able to print <code>dbDateTime</code> in SubSQL in readable form, you should 
define <code>SUBSQL_DATE_FORMAT</code> environment variablee (for example '%c'). To get more information about 
date time formats see documentation of <code>strftime<code> function. If <code>SUBSQL_DATE_FORMAT</code> is not defined,
 <code>dbDateTime</code> structure will be printed as normal structure
with integer component. SubSQL doesn't currently allow convertion of date from string during insert or update operations.<P>


<H2><A NAME = "www">API for development Web applications</A></H2>

New version of GigaBASE provides API for developing WWW applications.
It is very easy to perform Web database publishing with GigaBASE.
GigaBASE  server can either communicate with standard WWW server by
means of CGI requests, or it can serve HTTP requests itself.<P>
Interaction with Web server is based on three-tier model:

<PRE>
    Web Server   -&gt;     CGI stub     -&gt;    GigaBASE application
             CGI call          local socket connection
</PRE>

Using GigaBASE built-in HTTP server provides maximum performance, because in
this no communication and process creation overhead takes place.
In both cases the same API for receiving and unpacking requests
and constructing responses is used. So the same application
can be used for interaction with external Web server as well as
stand-alone HTTP server.<P>

GigaBASE application is request-driven program, receiving data from
HTML forms and dynamically generating result HTML page. Classes
<code>WWWapi</code> and <code>WWWconnection</code> provide simple and
convenient interface for getting HTTP requests, constructing HTML page and
sending reply back to WWW browser. Abstract class <code>WWWapi</code>
has two implementations: <code>CGIapi</code> and <code>HTTPapi</code>,
first of which implements protocol of interaction with Web server by means of
CGI mechanism, and the second - protocol of direct serving HTTP requests.<P>

Built-in HTTP server is able to handle two types of requests -
transfer HTML file find in place relative to the current working directory
in response to GET HTTP request and perform action specified by GET or POST
requests with parameters. Built-in HTTP server provides persistent connections -
server will not close connection with client immediately after sending
response, instead of this connection will be kept during some specified
interval of time. Also this built-in server supports concurrent requests
processing by several threads of control. But starting of threads should
be performed by client application.<P>

Virtual method <code>WWWapi::connect(WWWconnection& con)</code>
accept clients connection (either from CGISTUB program of from WWW browser).
This method returns <code>true</code> if connection is established.
In this case programmer should call
<code>CGIapi::serve(WWWconnection& con)</code> to receive and handle client's
requests. This method return <code>false</code> if and only if handler
of request returns <code>false</code>. Even if request was not correctly
received or could not be handled, <code>true</code> is returned by
<code>serve</code> method. The connection is always closed after return from
<code>serve</code> method. It is possible to start separate thread for
exceution of each <code>server</code> method.<P>

To construct responce to the request special overloaded <code>&gt;&gt;</code>
operators are provided in <code>WWWconnection</code> class. First line of
response should specify type of response body, for example:

<PRE>
Content-type: text/html\r\n\r\n
</PRE>

Two CR-LF character after this line separate HTTP header from the body.
Three encoding schemes can be used for constructing response body:

<OL>
<LI><B>TAG</B> - used for specifying HTML control elements. No conversion is
done for this encoding.
<LI><B>HTML</B> - with this encoding output characters which are special for
HTML (&lt; &gt; &amp; &qout;) are replaced with special symbolic names
(&qout;lt; &qout;gt; &qout;amp; &qout;qout;).
<LI><B>URL</B> - used for specifying call parameters in URL format.
Spaces are replaced with '+' character, all other special characters with
their hex code.
</OL>

To make switching between encoding more convenient, <code>WWWconnection</code>
class performs automatic switching between encodings. Initially <B>TAG</B>
encoding is always used. Then encodings are implicitly changed using the
following rules:

<PRE>
              TAG  -&gt; HTML
              HTML -&gt; TAG
              URL  -&gt; TAG
</PRE>

It certainly possible to explicitly specify encoding for the next output
operation by means of special <code>&lt;&lt;</code> operator, which accepts
one of the following constants: <code>TAG, HTML, URL</code>.<P>

Information about HTML form slots values or request parameters can be obtained
using <code>WWWconnection::get(char const* name, int n = 0)</code> method.
Optional second parameter is used only for getting value of selectors with
multiple selection allows option. If parameter with such name is not found,
<code>NULL</code> is returned. There are some mandatory parameters
which always should be present in all forms handled by GigaBASE:<P>

<TABLE BORDER>
<TR><TH>Parameter name</TH><TH>Parameter Description</TH></TR>
<TR><TD>socket</TD><TD>address of the server, used for constructing new links</TD></TR>
<TR><TD>page</TD><TD>symbolic name of the page, used for request dispatching</TD></TR>
<TR><TD>stub</TD><TD>name of CGI stub program always defined by API</TD></TR>
</TABLE><P>


<H2> <A NAME = "examples">Examples of GigaBASE applications</A></H2>

GigaBASE is shipped with some examples of database applications, which
can help you with creation of your own applications.<P>

<H3> <A NAME = "guess">Example: game "Guess an animal"</A></H3>
"Guess an animal" is very simple program which uses database to
store the game tree. Having very simple algorithm this program shows some elements of "artificial intelligence". The more information you provide to this
game, the more smarter will be it's behavior.<P>

This is example of "navigation-only" application -
no queries are used in this application at all. All navigation between
records (object) is done by means of references. Really this application
is more suitable for object oriented databases, but I include it in GigaBASE

<OL>
<LI>to illustrate how easy navigation by references can be done in GigaBASE,
<LI>because this program is some kind of my "trade mark" which I use in all
my databases.
</OL><P>


<H3> <A NAME = "testdb">Example: various types of queries</A></H3>

This application illustrates using of various types of database queries
and advantages of using inverse references. Classical Detail/Contract/Supplier
database scheme is used in this example. Compare number of lines in this
file with number of lines needed to implement this example using ODBC or
other RDBMS C API.<P>

<H3> <A NAME = "testperf">Performance test</A></H3>

This test allows to receive some results about GigaBASE performance for
all basic operations. This test inserts <I>N</I> records in the table,
then performs searches using T-tree and hash table, then sequential search and
sequential search with sorting. It is possible to specify level
of query parallelization in command line. By default no parallelization
is used. The following table contains results for some systems and
<I>N</I> = 1000000. In all tested systems size of operating memory is 64Mb,
and data is stored in normal operating system files (not in raw disk
partitions). Values in the table rows specifies time number of milliseconds
consumed by the operation which is calculated by dividing time returned
by <code>testperf</code> program by number of iterations.<P>

<TABLE BORDER>
<TR><TH>System</TH><TH>Insertion*)</TH><TH>Index search</TH><TH>Sequential search</TH><TH>Sequential search with sorting</TH></TR>
<TR><TD>Pentium-II 250, Windows NT 4.0</TD><TD>0.207</TD><TD>0.155</TD><TD>88 100</TD><TD>520 000</TD></TR>
<TR><TD>Pentium-II 250, Linux</TD><TD>0.070</TD><TD>0.128</TD><TD>90 200</TD><TD>458 000</TD></TR>
<TR><TD>Ultra-5, Sparc 270 Mhz, Solaric 2.6</TD><TD>0.137</TD><TD>0.263</TD><TD ALIGN="center">-</TD><TD ALIGN="center">-</TD></TR>
</TABLE><P>

*) doesn't include commit time<P>




<H3><A NAME = "bugdb">Bug tracking database</A></H3>

Example "Bug tracking database" illustrates developing Web application
using GigaBASE and WWW API. It can be used either with any WWW server
(for example Apache or Microsoft Personal Web Server) or with
built-in HTTP server. To compile BUGDB for interaction with external server,
define macro <code>USE_EXTERNAL_HTTP_SERVER</code>.
Database can be
accessed from any computer running some WWW browser. To build
<code>bugdb</code> application in Unix you should specify <code>www</code>
target to make utility.<P>

To run this BUGDB with external WWW server you should first customize your
WWW server.
It should be able to access <code>buglogin.htm</code> file and run
CGI script <code>cgistub</code>. Also user, under which CGI scripts will
be executed, should have enough permissions to establish connection with
GigaBASE application (by sockets). It is better to run GigaBASE application and
GigaBASE CGI scripts under the same user. For example, I have changed the
following variables in Apache configuration file:

<PRE>
httpd.conf:
        User konst
        Group users

access.conf:
        &lt;Directory /usr/konst/gigabase&gt;
        Options All
        AllowOverride All
        allow from all
        &lt;/Directory&gt;

        DocumentRoot /usr/konst/gigabase

srm.conf:
        ScriptAlias /cgi-bin/ /usr/konst/gigabase/
</PRE>

It is also possible not to change configuration of WWW server, but place
<code>cgistub</code> and <code>bugdb</code> programs in standard CGI
script directory and change in the file <code>buglogin.htm</code> path to
the <code>cgistub</code> program.
After preparing configuration files you should start WWW server.<P>

No configuration is needed when you are using built-in HTTP server.
Just make sure that user has enough permission to access port number 80
(default port for HTTP server). If some HTTP server is already started at your
computer, you should either stop it or specify another port for
built-in HTTP server. In last case you also need to specify the same port
in the settings of WWW browser to make it possible to establish connection with
right HTTP server. Also do not forget to specify real name of your computer
in ACTION field of buglogin.htm file.<P>

After starting <code>bugdb</code> application itself you can visit
<code>buglogin.htm</code> page in WWW browser and start to work with
BUGDB database. When database is initialized, "administrator" user is
created in the database. First time you should login as administrator using
empty password. Than you can create some other users/engineers and
change the password. BUGDB doesn't use secure protocol of passing passwords and
doesn't worry much about restricting access of users to the database.
So if you are going to use BUGDB in real life, you should first
think about protecting database from unauthorized access.<P>


<H3><A NAME = "clidb">Clients-Managers database</A></H3>

This yet another example of Web database publishing. This database
contains information about clients and managers. Each client and each manager belongs to
some segment (department). Managers can make remarks on status of a client from the same
segment to which manager belongs. Some managers has mini-administrator permissions and
they are allowed to edit/remove reports made by other managers. Information about
segments and mangers is maintained by database administrator.<P>

As well as BUGDB, this Web database example can work either through CGI interface with
some external HTTP server or use built-in HTTP server (last one is significantly
more efficient than interaction through CGI scripts). Look
<A HREF="#bugdb">previous section</A> for more information about configuration of
HTTP server. Do not forget to specify real name of your computer
in ACTION field of clilogin.htm file.<P>

After starting <code>clidb</code> application itself you can visit
<code>clilogin.htm</code> page in WWW browser and start to work with
CLIDB database. When database is initialized, "administrator" user is
created in the database. This database allows to specify IP address for the manager from
which this manager can login to the system. So user authentication is based on
the name and host computer IP address. Value '*' allows user to login from any host.
If you specify wrong IP address for the administrator and so are not able to login to
the database, you can invoke clidb as

<PRE>
       clidb <socket-name> login_from_any_host
</PRE>


CLIDB also can be considered as example of multithreaded Web database server.
There is special class QueueManager which can be used for maintaining pool of threads
and distributing user HTTP requests between these threads. If you recompile CLIDB
application with USE_QUEUE_MANAGER option set,
then CLIDB will spawn 8 threads for handling HTTP requests. In this case persistent
connection with client's WWW browsers are established (so there is no
extra overhead for establishing connecting for each HTTP request).<P>


<H2><A NAME = "quick">Quick start</A></H2>

When you are developing application for GigaBASE, you should first decide
which data and which classes you want to store in database. Then you
should describe format of database tables. Section
<A HREF="#table">Table</A> describes how to create type and table descriptors.
Do not forget to register table descriptors by <code>REGISTER</code> macro
(it should be done in some implementation module). If you are going
to redefine default GigaBASE error handler (for example, if you want to use
message window for reporting instead of <code>stderr</code>), you should
define your own database class and derive it from <code>dbDatabase</code>.
You should create instance of database class and make it accessible to
all application modules.<P>

Before you can do something with database, you should open it.
By checking of <code>dbDatabase::open()</code> return code you can
understand if database was successfully opened. Errors during database
opening doesn't cause application termination (but they are reported)
even with default error handler.<P>

Once you are certain that database is normally opened, you can start
to work with database. If your application is multithreaded and several threads
will work with the same database, you should attach each thread to the
database by <code>dbDatabase::attach</code> method. Before thread termination,
it should detached itself from database by invoking
<code>dbDatabase::detach()</code> method. If your application uses navigation
through database objects by references, you need some kind of root objects
which can be located without any references. Best candidate for the root
objects is the first record of the table. GigaBASE guarantee that new
records are always inserted at the end of the table. So first table record
is also the oldest record in the table.<P>

To access database data you should create a number of <code>dbQuery</code>
and <code>dbCursor</code> objects. If several threads are working with
database, each thread should have its own instances of query and
cursor objects. Usually it is enough to have one cursor for each table
(or two if your application also can update table records). But in case
of nested queries, using of several cursors may be needed.
Query objects are usually created for each type of queries. Query objects are
used also for caching compiled queries, so it will be good idea to
extend live area of query variables (may be make them static).<P>

There are four main operations with database: insert, select, update, remove.
First is done without using cursors, by means of global overloaded
template function <code>insert</code>. Selection, updating and deleting of
records is performed using cursors. To be able to modify table you should
use cursor for update. Cursor in GigaBASE is typed and contains instance
of object of table class. Overloaded <code>-&gt;</code> operator
of the cursor can be used to access components of current record
and also to update these components. Method <code>update</code>
copies data from cursor's object to the current table record.
Cursor's method <code>remove</code> will remove current cursor record,
method <code>removeAllSelected</code> will remove all selected records and
method <code>removeAll</code> will remove all records in the table.
Each transaction should be either committed by
<code>dbDatabase::commit()</code> or aborted by
<code>dbDatabase::rollback()</code> method. Transaction is started
automatically when first select, insert or remove operation is executed.<P>

Before exiting from your application do not forget to close database.
Also remember, that method <code>dbDatabase::close()</code> will automatically
commit last transaction, so if it is not what you want, then explicitly perform
<code>dbDatabase::rollback</code> before exit.<P>

So template of GigaBASE application can look something like this:
<PRE>
//
// Header file
//
#include "gigabase.h"

extern dbDatabase db; // create database object

class MyTable {
    char const* someField;
    ...
  public:
    TYPE_DESCRIPTOR((FIELD(someField)));
};

//
// Implementation
//
REGISTER(MyTable);

int main()
{
    if (db.open("mydatabase.dbs")) {
        dbCursor&lt;MyTable&gt; cursor;
        dbQuery q;

	char value[bufSize];

	q = "someField=",value;
	gets(value);
	if (cursor.select(q) &gt; 0) {
	    do {
	        printf("%s\n", cursor-&gt;someField);
	    } while (cursor.next());
        }
	db.close();
	return EXIT_SUCCESS;
    } else {
        return EXIT_FAILURE;
    }
}
</PRE>

To compile GigaBASE application you need to include header file
<code>"gigabase.h"</code>.
This header file includes other GigaBASE header files,
so make sure that GigaBASE directory is in compiler include directories list.
To link GigaBASE application you need GigaBASE library
(<code>"gigabase.lib"</code>
for Windows or <code>"libgigabase.a"</code> for Unix). You can either
specify full path to this library or place it in some default
library catalog (for example <code>/usr/lib</code> for Unix).<P>

GigaBASE will be able to handle non-ANSI character code sets if
library is compiled with <code>USE_LOCALE_SETTINGS</code> name defined.
In this case <code>strcoll()</code> functions will be used for
string comparison instead of <code>strcmp()</code> (<code>strcmp()</code>
still will be used for comparison of strings for equality).
To make this string comparisons and conversions (performed by
<code>toupper()</code> and <code>tolower()</code> functions) work perfectly,
you should set correct value of locale by <code>setlocale()</code>
function. Unicode is not supported in current release of GigaBASE.<P>

To build GigaBASE library just type <code>make</code> in GigaBASE directory.
There is no autoconfiguration utility included in GigaBASE distribution.
Most system dependent parts of code are compiled using
conditional compilation. There are two makefiles in GigaBASE distribution.
One for MS Windows with MS Visual C++ (<code>makefile.mvc</code>)
and another one for generic Unix with gcc compiler(<code>makefile</code>).
If you want to use Posix threads or some other compiler, you
should edit this makefile.
There is also <code>make.bat</code>, which just spawns
<code>nmake -f makefile.mvc</code> command.
Target <code>install</code> target in
Unix makefile will copy GigaBASE header files,
GigaBASE library and subsql utility
to directories specified by <code>INCSPATH, LIBSPATH</code> and
</code>BINSPATH</code> makefile variables correspondingly.
Default values of this variables are the following:

<PRE>
        INCSPATH=/usr/include
        LIBSPATH=/usr/lib
        BINSPATH=/usr/bin
</PRE><P>

Once your application starts to work, you will be busy with
support and extension of you application. GigaBASE is able to perform
automatic scheme evaluation for such cases as adding new field to the table and
changing type of the field. Programmer can also add new indices or remove
rarely used indices. Database trace can be switched on (by recompilation
GigaBASE library with <code>-DDEBUG=DEBUG_TRACE</code> compiler options) to
perform analysis of database functionality and efficiency of using indices.<P>

SUBSQL utility can be used for database browsing and inspection, performing
online backups, database recovery, importing data to and exporting data from
database.
GigaBASE will perform automatic recovery after system or application crash,
you should not worry about it. The only thing you can have to do manually
is stopping all database application if one of them is crashed leaving
database blocked.<P>

GigaBASE allows to declare queries as static variables.
But in this case destructors of these queries can be called <b>after</b> destructors of the static
objects from the GigaBASE library itself (because order of invoking destructors for different modules is 
not specified. To solve this problem, in GigaBASE some global objects are replaced with references.
As a result destructors are never called for these objects. But it leads to <i>memory leaks</i>
in application. These <i>memory leaks</i> can not actually cause some problems (like memory exhaustion), 
but it case warning in some memory-checking utilities. And many C++ programmers like to use such utilities 
to check if all emory is correctly deallocated. To avoid these warning for GigaBASE objects you can 
register with <code>atexit</code> system function static method <code>dbDatabase::clenup</code>, 
which will delete <b>all</b> objects allocated by GigaBASE.<P>


<H2><A NAME = "dbsize">Reducing initial size of the database file</A></H2>
By default the initial size of empty database file is 8 megabyte. Most of this space is 
reserved for object index (table which is used to translate object identifier into offset
of the object in the file). For some application it is desirable to reduce initial size of the 
database. It can be done in several ways.<P>

First of all, you can reduce value of <code>dbDefaultInitIndexSize</code> in 
<code>database.h</code> file. Default value of this parameter is 1024*1024. As far as size of 
each entry in of the object index is 4 bytes long and there are two copies of index (primary 
and shadow), it results 8 megabyte file. If typical number of object in your application is 
small then one million, you can choose the smaller value of this parameter. When number
of objects exceeds size of object index, it will be reallocated. So reducing value of this
doesn't set any limitations on size of database and number of objects - it just increase number
of possible index reallocation. Index reallocation is requires copying of old instance of the
index to the new location, so it is time consuming operation (but when the size of object index
is smaller than million, it will take fractions of second).<P>

You can even further reduce size of the database by reducing <code>dbDatabaseOffsetBits</code>
parameter in <code>class.h</code> file. But this parameter limits the maximal size of the 
database file and benefit in space is not so significant. So I do not recommend you to change 
this parameter. But if you want to support databases large than 4 gigabytes, you need to 
increase value of this parameters (default value is 32). When value of this parameters is
larger than 32, each entry in the object index is 8 bytes long instead of 4 bytes. So size
of the object index (and so initial size of the database) is doubled.<P>


<H2><A NAME = "sharing">Sharing of classes between different databases</A></H2>

Starting from version 2.27, GigaBASE supports sharing of
classes between several databases. To use this feature you should:<P>

<OL>
<LI>Register classes using <code>REGISTER_UNASSIGNED</code> macro.
<LI>Path pointer to dbDatabase as first parameter of <code>dbCursor</code> constructor.
<LI>Method <code>insert</code> is now member of </code>dbDatabase</code> class (if 
C++ compiler doesn't support member templates, you should define 
<code>NO_MEMBER_TEMPLATES</code> macro and path pointer to database as first parameter).
</OL><P>

For examle:

<PRE>
    class MyClass {
        ...
    };
    REGISTER_UNASSIGNED(MyClass);
    dbDatabase* db;
    dbCursor&lt;MyClass&gt; cursor(db);
    MyClass rec;
    if (cursor.select(q) == 0) {
        db->insert(rec);
    }
</PRE>


<H2><A NAME = "distribution">Distribution terms</A></H2>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the <A HREF="#Software">Software</A>), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:<P>

<A NAME="Software">
<B>
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</B>
</A><P>

I will provide e-mail support and help you with development of
GigaBASE applications.<P>
<HR>
<P ALIGN="CENTER"><A HREF="http://www.garret.ru/~knizhnik">
<B>Look for new version at my homepage</B></A><B> | </B>
<A HREF="mailto:knizhnik@garret.ru">
<B>E-Mail me about bugs and problems</B></A></P>
</BODY>
</HTML>
